2017-11-18 4 views
0

나는이 문제를 디버깅하는데 많은 시간을 보냈으며, 나는 익스프레스 서버의 POST와 GET 라우트에서 사용하고있는 firebase 데이터베이스 레퍼런스와 관련이 있다는 결론에 도달했다. 다음은 완전한 코드입니다. 내 프론트 엔드가 호출하는 첫 번째 경로는 router.get('/get-images', function(req, res) ...입니다. 콜백 함수에서 먼저 참조 firebaseApp.database().ref(/user_profile_images/${userId})을 설정합니다. 이 코드는 처음부터 끝까지 잘 작동합니다.Node Express + firebase-admin 서버 - GET의 POST 호출 코드에서 firebase 데이터베이스 참조 - 이유는 무엇입니까?

그러나 나중에 내가 POST 경로 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 경로가 .... 완료 잘 실행

답변

0

문제는 다음과 같습니다.

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

이미지를 변경하기 위해 수신기를 등록하지만 절대로 제거하지 못합니다. 리스너는 처음에는 현재 값으로 호출되지만 값이 변경 될 때마다 호출됩니다. 이벤트를 트리거하도록 POST 핸들러가 값을 변경합니다.

이 문제를 해결하려면 on 대신 once을 사용하십시오.

+0

이것은 ... 나는 단지 이것을 배우고 있으며 나는 최고의 JS 프로그래머가 아니며 나는 PHP 녀석이다. 여전히 JS의 비동기 실행에 대한 내 머리를 감싸려고 노력하고있다. 도움을 주셔서 감사합니다. –