Ich habe viel Zeit damit verbracht, dieses Problem zu debuggen, und ich bin zu der Schlussfolgerung gekommen, dass es sich um die Firebase-Datenbankreferenz handelt, die ich in meinen POST- und GET-Routen meines Express-Servers verwende. Im Folgenden finden Sie den vollständigen Code. Die allererste Route, die von meinem Frontend aufgerufen wird, ist router.get('/get-images', function(req, res) ...
. Beachten Sie, dass ich in der Callback-Funktion zuerst die Referenz firebaseApp.database().ref(/user_profile_images/${userId})
eingerichtet habe. Dieser Code funktioniert von Anfang bis Ende.Node Express + Firebase-Admin-Server - Firebase-Datenbank-Referenz in POST-Aufruf-Code in GET - warum?
jedoch später ich die POST Route router.post('/add-images', upload.single('userImage'), function(req, res) ...
nennen und das ist, wo die Dinge beginnen, wirklich seltsam bekommen - sobald die Ausführung von Code auf den Punkt, wo die Firebase Referenz firebaseApp.database().ref(
user_profile_images verwendet wird/$ {userId} ).push()...
es scheint an dieser Stelle Die Callback-Funktion, die zuvor in der GET-Route implementiert wurde, wird aufgerufen, und das ist der Punkt, an dem ich überhaupt nicht weiß, was passiert.
Nachstehend ist mein vollständiger Servercode, gefolgt von einem Beispieloutput, wo ich console.logs eingerichtet habe, um jeden Schritt in der Funktion zu "mappen" - achten Sie auf die Ausgabe, wenn sich die Zeilen von ADD IMAGES part 5 to GET IMAGES part ändern 1 - das ist der Punkt, dass die Ausführung Code aus der POST-Code in der Referenz Rückruf in der GET-Route zu rufen scheint
ADD IMAGES part 4
ADD IMAGES part 5
GET IMAGES part 1
GET IMAGES part 2
kompletter Servercode (minus gültige Schlüssel/db Namen/etc):
let express = require('express');
let cors = require('cors');
let bodyParser = require('body-parser');
const uuidv4 = require('uuid/v4');
let base64Img = require('base64-img');
var firebaseAdmin = require("firebase-admin");
let cloudinary = require('cloudinary');
let multer = require('multer');
let UserProfileImage = require('./utils/UserProfileImage');
let _ = require('lodash');
/**
* ========================
* firebase set up
*
* @type {Function}
*/
var firebaseServiceAccount = require('./somekeyfile.json');
let firebaseApp = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(firebaseServiceAccount),
databaseURL: 'https://somedb.firebaseio.com/'
});
// ========================
/**
* ========================
* couldinary configuration
*/
cloudinary.config({
cloud_name: 'somecloudname',
api_key: 'somekey',
api_secret: 'somesecret'
});
const CLOUDINARY_UPLOAD_PRESET = 'veeezmct';
let port = process.env.PORT || 8080;
// ========================
// ROUTES FOR OUR API
// ===================================
// get an instance of the express Router
let router = express.Router();
// test route to make sure everything is working
// (accessed at POST http://localhost:8080/image-controller-api/upload)
let upload = multer({
dest: 'uploads/',
limits: {
fileSize: 5 * 1024 * 1024 // no larger than 5mb, you can change as needed.
}
});
router.post('/add-images', upload.single('userImage'), function(req, res) {
// console.log("\n########################\n########################\n########################\n");
console.log('ADD IMAGES');
// make sure there is a user id before continuing
if (req.body.userId === undefined || req.file === undefined) {
return res.json({message: 'User ID and image file required to proceed'});
}
console.log('ADD IMAGES part 2');
// get the FB userId fromt he request body
const userId = req.body.userId;
const position = req.body.position;
const isPrimary = req.body.isPrimary;
let file = req.file;
console.log('ADD IMAGES part 3');
let uploadType = 'authenticated';
cloudinary.v2.uploader.upload(
req.file.path,
{
upload_preset: CLOUDINARY_UPLOAD_PRESET,
type: uploadType,
sign_url: true,
folder: userId
},
function(error, result) {
console.log('ADD IMAGES part 4');
// need to save the image url in the firebase
// user record here - create a new user profile image
//let ref = firebaseApp.database().ref(`user_profile_images/${userId}`);
let userProfileImage = new UserProfileImage();
userProfileImage.resourceId = result.public_id;
userProfileImage.userId = userId;
userProfileImage.url = result.secure_url;
userProfileImage.position = position;
userProfileImage.isPrimary = isPrimary;
userProfileImage.isPrivate = "false";
console.log('ADD IMAGES part 5');
// use 'child' and 'set' combination to save data
// in your own generated key
firebaseApp.database().ref(`user_profile_images/${userId}`)
.push().update(userProfileImage).then(function(ref1) {
console.log('ADD IMAGES part 6');
base64Img.requestBase64(
result.secure_url,
function(err, messageRes, body) {
console.log('ADD IMAGES part 7');
if (!err) {
console.log('SUCCESS ENCODING IMAGE');
return res.json({imageData: body});
} else {
console.log('ERROR ENCODING IMAGE');
return res.json({error: err});
}
}
);
}, function(error) {
console.log('ERROR AT END', error);
});
}
);
});
/**
* get user profile images by user ID
**/
router.get('/get-images', function(req, res) {
console.log("\n///////////////////////////////////////\n///////////////////////////////////////\n///////////////////////////////////////\n///////////////////////////////////////\n");
console.log('GET IMAGES');
let userId = req.query.userId;
firebaseApp.database().ref(`user_profile_images/${userId}`).on(
'value',
snapshot => {
console.log('GET IMAGES part 1');
// if we have valid objects to iterate through
if (snapshot.val()) {
console.log('GET IMAGES part 2');
// iterate through the objects to get each image url
// and base64 representation
// get the userProfileImages object list
let userProfileImages = snapshot.val();
// flag to determine how many requests have been completed
let completeRequests = 0;
// the total number of request to make which is the total
// number of userProfileImages to process
let numberOfRequestsToMake = Object.keys(userProfileImages).length;
// iterate through each of the user profile images
console.log('GET IMAGES part 3');
_.map(userProfileImages, (userProfileImage, key) => {
console.log('GET IMAGES LOOP ', completeRequests);
completeRequests++;
if (completeRequests === numberOfRequestsToMake) {
console.log('GET IMAGES part 4');
console.log('# of requests complete, return to client');
return res.json({ userProfileImages: userProfileImages });
}
}); // end _.map
} else {
console.log('ok sending default empty array');
return res.json({userProfileImages: {}});
}
},
errorObject => {
console.log('base64Img.requestBase64 result error');
return res.json({error: error});
}
);
});
// set up the server
let app = express();
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// REGISTER OUR ROUTES
// all of our routes will be prefixed with /image-controller-api
app.use('/image-controller-api', router);
// START THE SERVER
app.listen(port);
console.log('Listening...');
Hier ist die Befehlszeilenausgabe von jedem der c (Onsole.log) in meinem Code:
//////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////
GET IMAGES
GET IMAGES part 1
GET IMAGES part 2
GET IMAGES part 3
GET IMAGES LOOP 0
GET IMAGES LOOP 1
GET IMAGES LOOP 2
GET IMAGES LOOP 3
GET IMAGES LOOP 4
GET IMAGES part 4
# of requests complete, return to client
ADD IMAGES
ADD IMAGES part 2
ADD IMAGES part 3
ADD IMAGES part 4
ADD IMAGES part 5
GET IMAGES part 1
GET IMAGES part 2
GET IMAGES part 3
GET IMAGES LOOP 0
GET IMAGES LOOP 1
GET IMAGES LOOP 2
GET IMAGES LOOP 3
GET IMAGES LOOP 4
GET IMAGES LOOP 5
GET IMAGES part 4
# of requests complete, return to client
FIREBASE WARNING: Exception was thrown by user callback. Error: Can't set headers after they are sent.
at ServerResponse.setHeader (_http_outgoing.js:371:11)
Wichtiger Hinweis: Wenn ich nie die GET-Route in der lifecyle meiner app nennt, dann ist die POST-Route führt fein bis zur Fertigstellung ....
Das war es ... Ich lerne gerade das und ich bin nicht der beste JS-Programmierer, ich bin ein PHP-Typ - immer noch versuche ich meinen Kopf um asynchrone Ausführungen von JS zu wickeln. Danke für die Hilfe. –