다음 두 개 코드의 결과가 왜 달라지는지 이유와 제게 이해가 부족한 개념을 알고 싶습니다.
GPT에 물어보니 대답을 정확하게 못하길래,, 개드립 고수님들께 질문드립니다.
// Common code for exam
const express = require('express') const app = express() const router = express.Router()
function fn (req, res, next) { console.log('I come here') next('router') }
// Here : define route and mount rounter instance to app
app.listen(3000,(req,res) => console.log("Go!")); |
// case 1) first mount router instance /* result log I come here */
app.use('/',router); //(1)
router.get('/foo', fn, (req, res, next) => { console.log('I dont come here1') }) router.get('/foo', (req, res, next) => { console.log('I dont come here2') })
app.get('/foo', (req, res) => { console.log(' I come here too') res.end('good') }) |
// case 2) late mount router instance /* result log */
router.get('/foo', fn, (req, res, next) => { console.log('I dont come here1') }) router.get('/foo', (req, res, next) => { console.log('I dont come here2') })
app.get('/foo', (req, res) => { console.log(' I come here too') res.end('good') })
app.use('/',router); //(2) |
case1과 case2의 로그 출력 결과가 다른 이유를 이해하지 못하겠습니다.
왜 두번째 코드에서만 "I come here"가 미출력되는지 이해가 되지 않습니다.
두번째 코드에서 router 인스턴스가 동작을 안하는 것으로 보이네요.
Q.제가 생각하는 가정은 다음과 같은데, 제가 잘못 이해한 부분이 있을까요?
제가 express의 미들웨어 실행 등록 순서가 어떻게 정해지는지를 모릅니다...
- '/foo' 경로에 대한 app의 라우트가 먼저 등록된 후 router의 마운트가 나중에 실행됨.
- '/foo' 경로에 대한 라우트 핸들러 실행 순서는 app 내장 라우트에 등록된 다음 함수가 제일 처음임
(req, res) => {
console.log(' I come here too')
res.end('good')
}
- 제일 처음 실행된 함수에 의해 request-response 사이클이 종료되어 router 인스턴스의 핸들러는 스킵됨.
이 문제와 관련해서 제가 학습이 필요한 자바스크립트, node js, 익스프레스 등의 개념이 있다면 말씀부탁드립니다.
express 공식문서 보면서 개념 익히고 있는데, 부족한 부분을 인지하고 채울 수 있는 곳을 찾고자 합니다.
동탄올리버
간단한 호이스팅문제로 보이는데 확인해보세요. js는 호이스팅을 잘해줘야함미다
아임니더
제가 이해가 어려워서 그러는데
어느 객체가 호이스팅 문제가 있는지 간략한 설명 부탁드려요..
app.use()함수 호출 순서 차이와 호이스팅 개념을 연결 짓는게 힘들어서요.
동탄올리버
호이스팅: https://developer.mozilla.org/ko/docs/Glossary/Hoisting
middleware location: https://stackoverflow.com/questions/66968831/does-it-matter-where-i-place-app-usehelmet-within-the-app-use-statements
제가 질문을 제대로 안읽고 답변을 했네여 ㅈㅅㅈㅅ
미들웨어는 request 가 발생했을때 가장 상위에서 제일 먼저 반응합니다. express doc에 보면 가정하신부분이 맞을겁니다. 마운트시에 app.use보다 app.get이 먼저 반응해서 res.end로 끝내버리니 연결 종료된걸로 보이네요. doc에서도 app use를 상위로 올리라고 되어있지않나여? 본지오래되서 기억이안나네
아임니더
답변 및 링크 감사합니다.
다음 사이트 route 연습코드에서는 app.use()를 나중에 사용해서, 크게 상관없는줄 알고 있었네요.
https://expressjs.com/en/guide/using-middleware.html#middleware.application:~:text=)%0A%7D)-,Router%2Dlevel%20middleware,-Router%2Dlevel%20middleware
동탄올리버
반대로 말했네요 ㅋㅋㅋ 아래로내려야
아임니더
app.use()를 app.get()보다 상위에 올려야한다고 이해했습니다.
router객체를 app에 마운트하는 것이 app.use()에 역할인데, router 객체가 마운트되기 전에 app.get()에 의해 route가 등록되어 문제가 된것으로 보입니다.
하기 doc 링크에서 코드 순서대로 미들웨어함수의 순서가 정해진다는 사실을 알수 있었습니다.
https://expressjs.com/en/5x/api.html#router.param:~:text=Serve%20static%20files%20from%20multiple%20directories%2C%20but%20give%20precedence%20to%20%E2%80%9C./public%E2%80%9D%20over%20the%20others%3A
동탄올리버
https://stackoverflow.com/questions/20366765/express-js-app-usefunction-understanding-issue
app.use 는 app router 뒤로 쓰라고하네요
아임니더
찾아봐주셔서 감사합니다.
다만, 남겨주신 링크는 위 문제와 관련이 적은듯 하고, 제가 이해한 해결방식과 다른 듯합니다.
약 10년전 게시물이라 현재 express 버전과 차이가 있을 듯합니다.
질문자 코드에서도 router메소드를 사용하는 맥락이 제가 사용한 맥락과 다르네요.
저는 router()메소드를 클래스 함수로 사용하여, router 객체를 만들었습니다.
제가 이해한 해결방식은 app.use(path,router)를 app.get()보다 먼저 써야한다는 것입니다.
그래야 router 인스턴스에 등록된 route가 app 자체 route보다 먼저 실행될 수 있습니다.
middleware 실행 순서
(case1) router에 등록된 route -> app.get
(case2) app.get -> router에 등록된 route
동탄올리버
음 미들웨어는 무조건 라우트 전에 실행되어야 할텐데요. 예를들어, 제가 권한없는 상태에서 /upload 에 접근하려한다면 미들웨어에서 쳐내야 하잖아요?
express에서 middleware 는 app.use의 callback 함수로 등록을하는걸로 봐서는 route 객체하고는 별개인거 같아요.
위의 예시코드로는 res.end가 문제되는거 같습니다. connection 상태만 유지해준다면 위치는 상관없어보이는데요. res.end를 바꿔도 그런가요?
요기 참고해도 좋을거같아요
https://github.com/mazipan/nodejs-simple-restfull-with-express/tree/master
아임니더
app.get에 등록된 callback 함수도 미들웨어 스택에 저장된다고 저는 이해했습니다.
그래서, app.use('/',router)와 app.get('/foo',..) 코드 순서가 callback 함수의 실행 순서를 결정하는 것으로 이해했습니다.
case2에서 app.get()함수 로직을 res.end() 대신 next()를 사용하여 다음 미들웨어로 흐름을 넘겼습니다.
그 결과, router.get에 등록한 fn함수가 실행되는 것을 확인했습니다.
/*case2 결과*/
I come here too
I come here
case2 실행 순서 : '/foo' 경로 request > app.get > router.get
express에서 middleware 실행 순서는 middleware stack에 담겨진 순서대로 실행되는 것으로 알고있습니다.
next()를 사용하여 stack에 담긴 다음 middleware로 흐름을 넘겨주는 것으로 알고있습니다.
출처 - https://expressjs.com/en/guide/writing-middleware.html
남겨주신 rep의 app.js 코드 감사합니다.
확인한 결과, case2 코드같이 app.get과 router 객체를 같이쓸 때, path를 다르게 해서 쓰는게 났다고 생각되네요.
동일한 path에 대해서는 [callback ...] 같이 복수의 콜백을 router.get()등에 사용하는게 훨씬 보기 좋네요.
app.js에서는
1. app.use()로 복수의 미들웨어(logger 등)을 '/' 에 마운트. 즉, 모든 요청 발생시 처리됨.
2. app.use()로 복수의 router 객체를 각각 다른 path에 마운트 하였습니다.
3. 에러 핸들러 '/' 에 마운트.
실행 순서 : path 경로 request > loger > bodyParser.json() > ... > path에 따른 route
제가 잘못이해한 부분이 있다면 말씀부탁드립니다.
zrGgwK0rad
express 오래 한 사람으로서 댓글 막 길게 썼다지웠다 했는데
그냥 한마디만 하고 감
이렇게 코딩하지 마셈. 제발.
동탄올리버
배우는입장인데 물어볼수도 있죠 너무 빡빡하시네
zrGgwK0rad
애초에 route path로 요청을 받았을때 무슨 http method가 걸리는지, 어떤 middleware를 거치는지, 결과는 어떻게나오는지를 최대한 간단하게 표현하는게 먼저임
비상식적인 결과를 의도한 js코딩은 jsfuck에 지나지않음
아임니더
답변 감사합니다.
하기 연습코드 실습 도중, 코드에 app.use()가 명시되어 있지 않아서 2가지 케이스로 실습을 했었는데요.
어떤 결과가 정확하게 정상적인 결과인지 아직 초보라 알 수 없어서 여기에 질문남겼었습니다.
https://expressjs.com/en/5x/api.html#router.all:~:text=The%20following%20example%20illustrates%20next(%27router%27)%20usage.
말씀하신 뉘앙스로 보니, 1번 케이스가 정상적인 결과로 생각되지만, 지양해야할 코딩으로 생각되네요.
토이 프로젝트시, 요청에 대한 응답 프로세스가 명확하도록 작성해보겠습니다.