0

我正在编写一个快速应用程序来从照片中的地理坐标生成谷歌地图。我正在尝试使用 firebase 来保存有关图像的数据。代码完全正常工作,除非我将照片数据保存到 firebase 时,它​​会破坏下一页上的地图渲染,显示控制台中所有本地文件的连接错误,如下所示控制台错误

所以页面正在渲染,但地图没有加载,图像也没有。我保存到firebase的数据实际上正在保存,如果我删除将数据保存到firebase的功能,一切都会按预期工作。我认为这可能与推动响应的方式有关,但我不知所措。在我将数据保存到firebase的任何其他页面中,它都可以正常工作。

这是生成照片数据并将其保存到 Firebase 的路线的代码:

var express = require('express');
var router = express.Router();
var util = require('util');
var fs = require('fs');
var im = require('imagemagick');
var stormpath = require('express-stormpath');
var _ = require('lodash')
var Firebase = require('firebase');

router.post("/:campaignId", stormpath.loginRequired, function(req, res, next) {
    function gatherImages(files, callback) {

        //accept single image upload
        if (!_.isArray(files)) {
            files = [files];
        }

        var uploads = [];
        var count = 0;
        files.forEach(function(file) {

            fs.exists(file.path, function(exists) {
                if (exists) {
                    var name = req.body[file.originalname];
                    console.log(name);
                    var path = file.path;
                    var upFile = file.name;
                    uploads.push({
                        file: upFile,
                        imgPath: path,
                        caption: name || 'no comment'
                    });
                    count++;
                }
                if (files.length === count) {
                    callback(uploads);
                }
            });

        });

    }

    function getGeoLoc(path, callback) {
        im.readMetadata('./' + path, function(error, metadata) {
            var geoCoords = false;
            if (error) throw error;

            if (metadata.exif.gpsLatitude && metadata.exif.gpsLatitudeRef) {
                var lat = getDegrees(metadata.exif.gpsLatitude.split(','));
                var latRef = metadata.exif.gpsLatitudeRef;
                if (latRef === 'S') {
                    lat = lat * -1;
                }
                var lng = getDegrees(metadata.exif.gpsLongitude.split(','));
                var lngRef = metadata.exif.gpsLongitudeRef;
                if (lngRef === 'W') {
                    lng = lng * -1;
                }
                var coordinate = {
                    lat: lat,
                    lng: lng
                };
                geoCoords = coordinate.lat + ' ' + coordinate.lng;
                console.log(geoCoords);
            }

            callback(geoCoords);
        });
    }

    function getDegrees(lat) {
        var degrees = 0;
        for (var i = 0; i < lat.length; i++) {
            var cleanNum = lat[i].replace(' ', '');
            var parts = cleanNum.split('/');
            var coord = parseInt(parts[0]) / parseInt(parts[1]);
            if (i == 1) {
                coord = coord / 60;
            } else if (i == 2) {
                coord = coord / 3600;
            }
            degrees += coord;
        }
        return degrees.toFixed(6);
    }

    function processImages(uploads, callback) {
        var finalImages = [];
        var count = 0;
        uploads.forEach(function(upload) {
            var path = upload.imgPath;
            getGeoLoc(path, function(geoCoords) {
                upload.coords = geoCoords;
                finalImages.push(upload);
                count++;
                if (uploads.length === count) {
                    callback(finalImages);
                }
            });
        });
    }

    function saveImageInfo(finalImages, callback) {
        var campaignId = req.param('campaignId');
        var user = res.locals.user;
        var count = 0;
        var campaignPhotosRef = new Firebase('https://vivid-fire-567.firebaseio.com/BSB/userStore/' + user.username + '/campaigns/' + campaignId + '/photos');
        finalImages.forEach(function(image) {
            campaignPhotosRef.push(image, function(err) {
                if (err) {
                    console.log(err);
                } else {
                    count++;
                    if (finalImages.length === count) {
                        callback(finalImages);
                    } else {
                        return;
                    }
                }
            });
        });
    }

    if (req.files) {
        if (req.files.size === 0) {
            return next(new Error("Why didn't you select a file?"));
        }

        gatherImages(req.files.imageFiles, function(uploads) {
            processImages(uploads, function(finalImages) {
                saveImageInfo(finalImages, function(finalImages) {
                    var campaignId = req.param('campaignId');
                    console.log(res.req.next);
                    res.render("uploadMapPage", {
                        title: "File(s) Uploaded Successfully!",
                        files: finalImages,
                        campaignId: campaignId,
                        scripts: ['https://maps.googleapis.com/maps/api/js?key=AIzaSyCU42Wpv6BtNO51t7xGJYnatuPqgwnwk7c', '/javascripts/getPoints.js']
                    });
                });
            });
        });

    }

});

module.exports = router;

这是我编写的唯一一个试图将多个对象推送到 firebase 的文件。这是我第一次使用 Firebase 和 Stormpath,因此我们将不胜感激。另一件可能有用的事情是问题发生时终端输出的错误:

POST /uploaded/-JapMLDYzPnbtjvt001X 200 690.689 ms - 2719

/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/firebase/lib/firebase-node.js:24
?a:null}function Db(a){try{a()}catch(b){setTimeout(function(){throw b;},Math.f
                                                                    ^
TypeError: Property 'next' of object #<IncomingMessage> is not a function
    at fn (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:899:25)
    at EventEmitter.app.render (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/application.js:532:5)
    at ServerResponse.res.render (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:904:7)
    at /Users/jpribesh/Desktop/Code/BanditSignBoss/routes/campaigns.js:20:25
    at Array.forEach (native)
    at /Users/jpribesh/Desktop/Code/BanditSignBoss/routes/campaigns.js:16:18
    at /Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/firebase/lib/firebase-node.js:25:533
    at Db (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/firebase/lib/firebase-node.js:24:165)
    at Ye (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/firebase/lib/firebase-node.js:124:216)
    at Ze (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/firebase/lib/firebase-node.js:123:818)

更新:似乎连接错误不一致。有时图像显示得很好,有时只有一些图像出现连接错误,而其他时候包括谷歌地图脚本在内的所有内容都会出现连接错误。这真的让我不知道问题是什么。非常感谢任何帮助或建议!

更新 2:我更改了将图像数据保存到 firebase 的函数以使用 firebase 推送函数回调(以指示完成),并在运行的 forEach 循环上添加了长度检查以保存每个图像的数据。请参阅上面的更新代码。现在,对于在终端中上传的每个图像,我都收到以下错误,但连接错误消失了:

    Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (http.js:689:11)
    at ServerResponse.header (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:666:10)
    at ServerResponse.send (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:146:12)
    at fn (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:900:10)
    at View.exports.renderFile [as engine] (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/jade/lib/jade.js:325:12)
    at View.render (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/view.js:93:8)
    at EventEmitter.app.render (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/application.js:530:10)
    at ServerResponse.res.render (/Users/jpribesh/Desktop/Code/BanditSignBoss/node_modules/express/lib/response.js:904:7)
    at /Users/jpribesh/Desktop/Code/BanditSignBoss/routes/campaigns.js:20:25
    at Array.forEach (native)
4

1 回答 1

0

好的,我终于在这里找到了问题。我做了一些事情来解决我的问题。首先,我将路由转换为正确使用 next 以分离出路由的每个部分,它处理图像,然后保存,然后渲染。这是该文件中的更新代码:

    var express = require('express');
    var router = express.Router();
    var util = require('util');
    var fs = require('fs');
    var im = require('imagemagick');
    var stormpath = require('express-stormpath');
    var _ = require('lodash')
    var Firebase = require('firebase');

    function processData(req, res, next) {

        function gatherImages(files, callback) {

            //accept single image upload
            if (!_.isArray(files)) {
                files = [files];
            }

            var uploads = [];
            var count = 0;
            files.forEach(function(file) {

                fs.exists(file.path, function(exists) {
                    if (exists) {
                        var name = req.body[file.originalname];
                        console.log(name);
                        var path = file.path;
                        var upFile = file.name;
                        uploads.push({
                            file: upFile,
                            imgPath: path,
                            caption: name || 'no comment'
                        });
                        count++;
                    }
                    if (files.length === count) {
                        callback(uploads);
                    }
                });

            });

        }

        function getGeoLoc(path, callback) {
            im.readMetadata('./' + path, function(error, metadata) {
                var geoCoords = false;
                if (error) throw error;

                if (metadata.exif.gpsLatitude && metadata.exif.gpsLatitudeRef) {
                    var lat = getDegrees(metadata.exif.gpsLatitude.split(','));
                    var latRef = metadata.exif.gpsLatitudeRef;
                    if (latRef === 'S') {
                        lat = lat * -1;
                    }
                    var lng = getDegrees(metadata.exif.gpsLongitude.split(','));
                    var lngRef = metadata.exif.gpsLongitudeRef;
                    if (lngRef === 'W') {
                        lng = lng * -1;
                    }
                    var coordinate = {
                        lat: lat,
                        lng: lng
                    };
                    geoCoords = coordinate.lat + ' ' + coordinate.lng;
                    console.log(geoCoords);
                }

                callback(geoCoords);
            });
        }

        function getDegrees(lat) {
            var degrees = 0;
            for (var i = 0; i < lat.length; i++) {
                var cleanNum = lat[i].replace(' ', '');
                var parts = cleanNum.split('/');
                var coord = parseInt(parts[0]) / parseInt(parts[1]);
                if (i == 1) {
                    coord = coord / 60;
                } else if (i == 2) {
                    coord = coord / 3600;
                }
                degrees += coord;
            }
            return degrees.toFixed(6);
        }

        function processImages(uploads, callback) {
            var finalImages = [];
            var count = 0;
            uploads.forEach(function(upload) {
                var path = upload.imgPath;
                getGeoLoc(path, function(geoCoords) {
                    upload.coords = geoCoords;
                    finalImages.push(upload);
                    count++;
                    if (uploads.length === count) {
                        callback(finalImages);
                    }
                });
            });
        }


        if (req.files) {
            if (req.files.size === 0) {
                return next(new Error("Why didn't you select a file?"));
            }

            gatherImages(req.files.imageFiles, function(uploads) {
                processImages(uploads, function(finalImages) {
                    req.finalImages = finalImages;
                    req.campaignId = req.param('campaignId');
                    next();
                });
            });
        }

    }

    function saveImageInfo(req, res, next) {
        var user = res.locals.user;
        var count = 0;
        var campaignPhotosRef = new Firebase('https://vivid-fire-567.firebaseio.com/BSB/userStore/' + user.username + '/campaigns/' + req.campaignId + '/photos');
        var finalImages = req.finalImages;
        finalImages.forEach(function(image) {
            campaignPhotosRef.push(image, function(err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log('Data saved successfully: ' + image);
                    count++;
                    if (req.finalImages.length === count) {
                        next();
                    }
                }
            });
        });

    }




    router.post("/:campaignId", stormpath.loginRequired, processData, saveImageInfo, function(req, res) {
        res.render("uploadMapPage", {
            title: "File(s) Uploaded Successfully!",
            files: req.finalImages,
            campaignId: req.campaignId,
            scripts: ['https://maps.googleapis.com/maps/api/js?key=AIzaSyCU42Wpv6BtNO51t7xGJYnatuPqgwnwk7c', '/javascripts/getPoints.js']
        });

    });

    module.exports = router;

然后我意识到在我的问题中包含的跟踪堆栈中,它的一部分正在回溯到我正在使用 firebase 的另一个文件。我在提取数据时使用了对 .on() 的调用而不是使用 .once() 。在重新组织我的路线并将所有对 .on 的调用更改为 .once 以获取 Firebase 数据之后,一切现在都可以正常工作。我认为这里真正的问题是在我的 firebase 调用中使用 .on() 而不是 .once() 因为 .on() 持续监视事件,而不是 .once 显然只监视一次。

于 2014-11-18T02:03:47.640 回答