【问题标题】:Node Express + firebase-admin server - firebase database reference in POST calling code in GET - why?Node Express + firebase-admin 服务器 - GET 中 POST 调用代码中的 firebase 数据库参考 - 为什么?
【发布时间】:2018-05-02 10:22:44
【问题描述】:

我花了很多时间调试这个问题,我得出的结论是它与我在我的 express 服务器的 POST 和 GET 路由中使用的 firebase 数据库引用有关。以下是完整的代码。我的前端调用的第一个路由是router.get('/get-images', function(req, res) ... 请注意,在回调函数中,我首先设置了引用firebaseApp.database().ref(/user_profile_images/${userId})。这段代码从头到尾都运行良好。

但是后来我调用了 POST 路由 router.post('/add-images', upload.single('userImage'), function(req, res) ...,这就是事情开始变得非常奇怪的地方 - 一旦代码执行到使用 Firebase 引用的地步 firebaseApp.database().ref(user_profile_images/${userId}).push()...在这一点上,回调函数似乎在之前的某个时间点首先在 GET 路由中实现,正在被调用,这就是我完全不知道发生了什么的地方。

以下是我的完整服务器代码,然后是示例输出,其中我已将 console.logs 设置为“映射”函数中的每个步骤 - 当行从 ADD IMAGES 第 5 部分更改为 GET IMAGES 第 1 部分时,请注意输出- 这就是来自 POST 的执行代码似乎在 GET 路由的引用回调中调用代码的点

ADD IMAGES part 4
ADD IMAGES part 5
GET IMAGES part 1
GET IMAGES part 2

完整的服务器代码(减去有效密钥/数据库名称/等):

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...');

这是我代码中每个 console.log() 的命令行输出:

//////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////

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)

重要提示:如果我从未在我的应用程序的生命周期中调用 GET 路由,那么 POST 路由可以正常执行直到完成......

【问题讨论】:

    标签: javascript node.js reactjs express cloudinary


    【解决方案1】:

    问题出在这一点:

    firebaseApp.database().ref(`user_profile_images/${userId}`).on(
            'value',
    

    您正在为图像更改注册一个侦听器,但从未将其删除。侦听器最初将使用当前值调用,但随后每次值更改时都会调用它。您的 POST 处理程序会更改值以触发事件。

    要解决此问题,请使用 once 而不是 on

    【讨论】:

    • 就是这样......我只是在学习这个,我不是最好的 JS 程序员,我是一个 PHP 人 - 仍然试图围绕 JS 的异步执行。谢谢你的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 2020-12-22
    • 2020-06-20
    • 2019-03-24
    • 2015-05-17
    相关资源
    最近更新 更多