0

写真の地理座標から Google マップを生成するエクスプレス アプリを作成しています。画像に関するデータを保存するために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)

更新: 接続エラーに一貫性がないようです。画像が正常に表示される場合もあれば、一部の画像のみで接続エラーが発生する場合もあれば、Google マップ スクリプトを含むすべてで接続エラーが発生する場合もあります。これは本当に問題が何であるかわからないようになっています。どんな助けや提案も大歓迎です!

更新 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

OK私はついにここで問題を理解しました。私は自分の問題を解決するためにいくつかのことをしました。最初に、ルートを次に使用するように変換して、ルートの各部分を適切に分離し、画像を処理して保存し、レンダリングします。そのファイルから更新されたコードは次のとおりです。

    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 を使用していた別のファイルにトレースバックしていることに気付きました。ルートを再編成し、firebase データの .on へのすべての呼び出しを .once に変更した後、すべてが適切に機能するようになりました。ここでの本当の問題は、.once() が .once ではなく継続的にイベントを監視しているため、firebase 呼び出しで .once() の代わりに .on() を使用したことだと思います。

于 2014-11-18T02:03:47.640 に答える