JS/Node.js

[node.js] Nodejs Express 서버를 사용해보았다

kth990303 2021. 3. 31. 00:24
반응형

인프런 조현영님의 Node.js 교과서 강좌 6강을 수강해보았다.

현재 미들웨어 특성까지 강의를 들었는데, 생각보다 정보량이 많아 블로그에 정리해보려고 한다.


인프런 강좌 조현영님의 Node.js 교과서를 수강하고

복습 겸 요약한 내용을 담은 포스팅입니다.



const express=require('express');
const path=require('path');
const app=express();

// process.env.PORT 로 설정할 수 있으나, 나중에 배움.
app.set('port', process.env.PORT || 3000);
app.get('/', (req, res)=>{
    res.sendFile(path.join(__dirname, 'index.html'));
});

app.post('/', (req, res)=>{
    res.send('hello expresss');
});

app.get('/about', (req, res)=>{
    res.send('hello expresss');
});

app.post('/about', (req, res)=>{
    res.send('hello expresss');
});

app.listen(app.get('port'), ()=>{
    console.log('서버 실행');
});

만약 express가 깔려있지 않다면 npm으로 npm i express를 입력해 설치해주자.

path를 사용하는 이유는 깔끔함 또는 보안 때문인데, 아무래도 경로를 직접 드러내는 것보다 path.join으로 설정해준 후, __dirname과 같은 현재 디렉토리를 가리키게 해주면 더 깔끔하고 보안상으로도 좋아질 듯하다.

 

app.set

변수를 세팅해줄 때 set을 사용한다. 

이 코드에서는 포트번호를 3000번으로 설정하는 데에 app.set을 이용해주었다.

app.get, app.post

'GET', 'POST' method로 request가 들어올 때 처리해주는 코드이다.

참고로 익스프레스를 사용하기 전엔 res.writeHead(), res.end()를 사용했었는데, 익스프레스에선 res.send로 data를 바로 응답해줄 수 있다. 그리고 res.end(JSON.stringfy(...)); 또한 res.json({});로 바로 응답해줄 수 있다. 역시 편리한 익스프레스

 

참고로 넓은 범위, 또는 요청될 수 있는 범위가 넓을수록 밑에 작성해주어야 한다.

예를 들어 '/index/:name' 주소의 app.get (라우터 매개변수 name을 와일드카드로 설정해주었다. java의 와일드카드와 같은 개념이라 보면 된다.) 이 위에 있고, '/index/java' 주소의 경우만 따로 다른 처리를 해주고 싶어서 예외를 둔 코드의 app.get이 아래에 있으면, /index/java로 접속할 경우 밑에 코드가 실행되는 것이 아닌 위에 코드로 실행된다.

express 코드는 위에서부터 아래로 처리하기 때문이다.

 

이러한 app.get, app.post 등을 라우터 라고 한다.

 

참고로 한 라우터 내에서 res.send (res.sendFile, res.json, res.writeHead 포함) 등 응답을 2번 이상하면 'cannot set headers after they are sent to the client'

에러가 뜬다.

stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client

 

Error: Can't set headers after they are sent to the client

I'm fairly new to Node.js and I am having some issues. I am using Node.js 4.10 and Express 2.4.3. When I try to access http://127.0.0.1:8888/auth/facebook, i'll be redirected to http://127.0.0.1:...

stackoverflow.com

위 글을 읽어보면 좋을 듯하다. 굉장히 많이 겪는 에러라고 한다. (나도 앞으로 또 많이 겪겠지...)

app.use 와 미들웨어

미들웨어를 처리할 때 우리는 app.use를 쓴다. 

미들웨어란 요청을 받아들이고, 응답을 보내기 전에 작동되는 함수를 말한다.

express에서 미들웨어는 함수로 쓰인다.

위 코드의 app.set, app.get 사이에 app.use로 된 코드를 추가해보겠다.

.
.
.
// process.env.PORT 로 설정할 수 있으나, 나중에 배움.
app.set('port', process.env.PORT || 3000);

app.use((req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
})
app.get('/', (req, res)=>{
    res.sendFile(path.join(__dirname, 'index.html'));
});

app.post('/', (req, res)=>{
    res.send('hello expresss');
});
.
.
.

app.use에서 next()가 없으면 다음 미들웨어가 실행되지 않아 다음 응답이 실행되지 않을 것이다.

참고로 app.use 자체가 미들웨어가 아니고 (req, res, next)=>{} 이 함수가 미들웨어다.

 

nodejs express 또한 일반적인 다른 언어와 마찬가지로 위에서부터 아래로 코드가 실행되므로

아래와 같은 순서대로 실행이 된다.


  1. app.set으로 먼저 포트번호가 설정되고,
  2. '모든 요청에 실행되고 싶어요' 가 작동이 된 후,
  3. next() 함수가 있으므로 다음 미들웨어가 실행된다.
  4. app.get 라우터 중 요청 주소에 맞는 함수가 실행된다. (req, res)=> {} 이 부분이 미들웨어이므로, 적절한 주소를 찾으면 이 부분이 실행된다. 없으면 404 에러를 띄우게 되겠다.

참고로 아래와 같이 코드를 짜도 된다.

app.use((req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
}, (req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
}, (req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
});

위 코드의 경우, next() 함수로 인해 다음 미들웨어인 (req, res, next)=>{} 가 실행되고, 

또 그 안의 next()로 인해 다음 미들웨어가 실행된다.

이제 app.use 안의 마지막 next()가 실행되면서, app.get 라우터 안의 미들웨어를 실행하게 되겠다.

 

app.use를 이용한 에러처리

에러가 발생할 경우를 대비해 아래와 같이 에러를 짰다고 해보자. (에러를 스스로 만들은 코드라 보면 된다)

아래의 코드같은 경우 express 서버가 에러가 났음을 확인하고 스스로 에러창을 띄워준다.

app.use((req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
}, (req, res, next)=>{
    throw new Error('에러가 존재하잖아 개발자야');
});

에러를 띄워주는 express 서버

그런데 개발자 입장에서는 에러가 어디서 났는지 알 수 있으니 매우 친절하다고 생각하겠지만,

크래커(나쁜 해커)가 보기엔 경로가 다 뜨니까 크래킹하기 매우 쉬운 코드가 되겠고,

일반인이 보기엔 자기가 뭔가를 잘못 건드린줄 알고 우왕좌왕하고 울고불고 난리가 날 수 있다.

만약 내가 코딩의 ㅋ도 모르는데 위와 같은 창이 떴으면 바이러스걸린 줄 알고 as센터에 달려갔을 것 같다.

 

따라서 우리는 에러가 났을 때 처리를 스스로 관리해주는 것이 좋다.

어떻게 하냐? 바로 위에서 배운 미들웨어를 이용해서 에러처리를 한다~

 

app.listen 바로 위에, 즉 모든 라우터의 맨 밑에 이 코드를 작성하도록 한다.

app.use((err, req, res, next)=>{
    console.error(err);
    res.status(404).send('에러났잖아 이 멍청한 개발자야');
});

에러 미들웨어는 반드시 4개 인자, 그리고 위 순서를 정확히 지켜줘야한다.

그렇지 않으면 익스프레스 서버가 에러 미들웨어로 인지하지 않고 단순한 그냥 미들웨어로 인식한다.

실제로 예전에 코딩하다가 저 부분 실수해서 3시간 날렸던 시절을 기억하자...

 

참고로 status(404)를 적지 않으면 status가 200인 상태로 처리가 된다.

200은 성공을 의미한다.

그리고 실무에선 보통 서버쪽에서 404 에러가 아니어도, status를 브라우저에선 404로 주로 띄운다고 한다. 

500 에러는 서버 쪽 문제이기 때문에 이걸 띄워주는 순간 여기가 서버의 취약점임이 알려지는 것이나 다름없어 보안 상 위험할 수 있다고 한다.

 

 

그런데 위 코드는 일부러 에러를 던져준 경우이다.

솔직히 에러를 일부러 내는 경우가 흔할까? 

에러에 미친 사람이 아닌 이상, 대부분은 의도치 않게 에러가 날 것이다.

따라서 아래와 같이 코드가 짜여지는 경우가 흔할 것이다.

 

app.use((req, res, next)=>{
    console.log('모든 요청에 실행되고 싶어요');
    next();
}, (req, res, next)=>{
    try{
        // not defined abcde -> error
        console.log(abcde);
    } catch(err){
        next(err);
    }
});

실수로 문자열에 ""를 붙이지 않아 에러가 발생했다고 하자.

그러면 try문에서 에러가 날테니 next(err)로 넘어갈 것이다.

이렇게 next() 안의 인자에 에러가 있다면 다음 미들웨어로 넘어가긴 하는데, 에러 처리 미들웨어로 넘어간다.


요즘 nodejs에 다시 흥미가 붙고 있다. spring 공부도 하려 했는데 nodejs 공부하느라 못했다. (술을 안먹고 spring 공부했으면 됐잖아)

 

생산성이 간결하고 자바스크립트가 실무에 가까운 언어라 그런가 nodejs로 이것저것 만들어보고 aws로 배포해보는 경험을 겪어 백엔드 개발 경험을 키우면 스프링 공부에 더 많은 도움이 되지 않을까 싶어 nodejs도 다시 건드려보게 된 것 같다.

 

6~7월까지 완강할 수 있도록 해봐야겠다.

반응형