나는이 문제를 디버깅하는데 많은 시간을 보냈으며, 나는 익스프레스 서버의 POST와 GET 라우트에서 사용하고있는 firebase 데이터베이스 레퍼런스와 관련이 있다는 결론에 도달했다. 다음은 완전한 코드입니다. 내 프론트 엔드가 호출하는 첫 번째 경로는 router.get('/get-images', function(req, res) ...
입니다. 콜백 함수에서 먼저 참조 firebaseApp.database().ref(/user_profile_images/${userId})
을 설정합니다. 이 코드는 처음부터 끝까지 잘 작동합니다.Node Express + firebase-admin 서버 - GET의 POST 호출 코드에서 firebase 데이터베이스 참조 - 이유는 무엇입니까?
router.post('/add-images', upload.single('userImage'), function(req, res) ...
전화 일들이 정말 이상한 받기 시작 곳이에
- 코드 실행이 중포 기지의 참조 firebaseApp.database().ref(
user_profile_images 사용되는 지점에 도달하면/$ {userId를} ).push()...
는이 시점에서 보인다 이전에 GET 라우트에서 구현 된 콜백 함수가 호출되기 시작했습니다. 그리고 이것은 내가 무엇이 계속 진행되고 있는지 전혀 알지 못하는 곳입니다.
다음은 필자가 작성한 완전한 서버 코드입니다. 여기서 console.logs를 설정하여 각 단계를 '맵핑'할 수 있습니다 - 출력에주의를 기울여서 이미지를 추가하는 부분에서 이미지 부분을 가져 오는 부분까지 변경됩니다
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...');
: - 1이는 POST에서 해당 실행 코드는 GET 경로
ADD IMAGES part 4
ADD IMAGES part 5
GET IMAGES part 1
GET IMAGES part 2
전체 서버 코드 (마이너스 유효 키/DB 이름/등)에서 참조 콜백 코드를 호출하는 것 지점입니다
다음은 각 명령 행에서 출력되는 명령 행입니다 onsole.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 경로가 .... 완료 잘 실행
이것은 ... 나는 단지 이것을 배우고 있으며 나는 최고의 JS 프로그래머가 아니며 나는 PHP 녀석이다. 여전히 JS의 비동기 실행에 대한 내 머리를 감싸려고 노력하고있다. 도움을 주셔서 감사합니다. –