[생활코딩][WEB3] Express

2020. 8. 30. 14:28강의/생활코딩

Express는 nodejs위에서 돌아가는 프레임 워크이다.

주로 자바스크립트로 서버를 구현할때 사용되는데, 사용자의 요청에 따른 라우팅이 깔끔하게 표현된다.

졸업 프로젝트로 한번 사용해봤을 뿐, 제대로 공부해본 적이 없어서 강의를 듣게 되었다.

강의 전체의 내용을 정리하기보단, 잊기 쉬운것들을 간략하게 정리해둘 것이다.

 

1. 화살표 함수는 return이 생략된것

app.get("/", (req, res) => {
  res.send("Hello World!");
});

 

위와 같이 화살표 함수로 표현된 함수는 아래와 동일한 의미이다.

app.get("/", function(req, res) {
  return res.send("Hello World!");
});

 

2. Route Parameters

app.get("/page/:pageId", (req, res) => {
  res.send(req.params);
});

위와 같이 URL로 들어온 값은 ' : ' 를 통해 이름을 부여할 수 있고, req.params에 객체형태로 값이 담긴다.

예를들어 localhost:3000/page/HTML 로 요청을 보내온다면

req.params = {"pageId" : "HTML"} 가 된다.

따라서 req.params.pageId로 접근하여 사용자가 요청한 URL의 값을 읽을 수 있다.

이렇게 parameter를 이용하면 기존의 queryString방식보다 간단하고, 깔끔하게 구현된다.

 

3. redirect

Post방식의 메소드를 통해 무언가 등록을 한후, 돌아갈 페이지를 지정할때 redirect메소드를 사용할 수 있다.

* req와 res 순서는 바뀌면 동작하지 않는다 !! 순서 중요 ...

 

4. Express 미들웨어 -  body-parser

Express의 꽃은 라우팅과 미들웨어이다.

미들웨어란, 간단하게 설명하여 내가 구현하지 않은 유용한 기능들이 따로 정의되어있는 것이다.

Express는 다양한 미들웨어를 제공하는데, 그 중 body-parser를 사용해보았다.

const bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({ extended: false }));

body-parser미들웨어를 사용하기 위해서는 위와 같은 선언과 정의가 필수적이다.

app.use를 통해, bodyParser.urlencoded를 통해 만들어진 미들웨어가 이 프로젝트에서 사용될 수 있게 된다.

body-parser 미들웨어의 역할은 post로 전송받은 데이터를 분석하여 body객체를 내어주는 기능이 대표적이다.

app.post("/create_process", (req, res) => {
  var body = "";
  req.on("data", function (data) {
    body = body + data;
  });
  req.on("end", function () {
    var post = qs.parse(body);
    var title = post.title;
    var description = post.description;
    fs.writeFile(`data/${title}`, description, "utf8", function (err) {
      res.redirect(302, `/page/${title}`);
    });
  });
});

위의 코드가 미들웨어를 사용하지 않은 본래의 코드이다.

post방식의 요청에는 데이터가 들어있는데, 데이터가 매우 클 경우 나눠져서 들어오게된다. (네트워크때 배운 일정 크기의 packet생각하면 될듯 !!). 연속해서 들어오는 데이터를 body에 덧붙이는 형식인데, 다 받은 경우 그것을 qs.parse를 통해 내용만 파싱한후 사용한다.

이러한 과정들을 내부적으로 지닌 미들웨어가 body-parser이다.

var post = req.body;
  var title = post.title;
  var description = post.description;
  fs.writeFile(`data/${title}`, description, "utf8", function (err) {
    res.redirect(302, `/page/${title}`);
  });

위에서 body-parser를 사용하기 위한 선언과 정의를 해주었다면, post요청 req에는 body라는 객체가 포함되어있다.

body란 미들웨어를 사용하지 않은 곳에서 data를 연속해서 받아서 덧붙이고 가공하는 작업을 미들웨어를 통해 해둔 객체이다.

위의 두 코드를 비교해보면 확실히 미들웨어를 사용한 쪽이 더욱 깔끔하다. 

+) Express가 업데이트 되면서 body-parser를 불러오지 않아도 req의 body를 사용할 수 있게 업데이트 되었다고 한다 ....!

미들웨어가 무엇이고 어떤식으로 사용되는지 이해하는데에 의의를 두자 ...

 

5. Express미들웨어 - Compression

Compression 미들웨어는 컨텐츠를 압축하여 전송할때 사용하는 미들웨어이다.

사용법은 아주 간단하다. compression모듈을 require하고 app.use를 통해 사용하기만 하면된다.

compression의 역할은, 본문의 내용을 내부적으로 zip파일로 압축한다.

브라우저는 이 zip파일을 풀어서 화면에 표시해주는 것이다. 사용자가 많을경우 이와같이 압축하여 데이터를 보내는 것은 성능에 큰 차이가 날 수 있다.

 

6. 미들웨어 만들기

미들웨어는 위에서 보는것과 같이 app.use를 통해 사용할 수 있다.

그리고 그 미들웨어를 리턴해주는 함수가 use의 파라미터로 들어가게 된다.

즉, app.use(function)의 형태로 미들웨어를 사용할 수 있고,  함수를 정해진 규칙에따라 직접 구현한다면, 자신만의 미들웨어를 만들어 사용할 수 있는 것이다.

이때 함수는 req,res,next 순서로 parameter를 갖는다.

next는 함수로써, 그다음 실행될 미들웨어를 실행하도록 해준다.

실습코드 예제를 통해 이해를 해보면, 약간 전역번수의 느낌이 나는 것 같다...

 

위의 코드중 fs.readdir부분은 get방식의 라우팅함수에 모두 들어가는 내용이다.

이것을 미들웨어로 따로 빼두면, get요청이 올때마다 filelist를 읽지않고도 req.list에 filelist를 넣음으로써 해결할 수 있다. 

즉, app.use를 통해 filelist를 req.list에 할당한다음 next()를 통해 구체적인 라우팅 요청에 대한 처리를 하는 것이다.

한편, 이렇게 하면 filelist를 읽어오지 않아도 되는 라우팅 함수들도 전부 filelist를 읽는 비효율성이 문제가 될 수 있다.

따라서, app.use구문을 아래와 같이 변경할 수 있다.

app.get("*",(req,res,next)=>{
fs.readdir("./data", function(error,fillist){
request.list = filelist;
next();
});
});

get요청의 path에 *을 넣으면, get으로 오는 모든 요청에 대해 이 미들웨어를 선행적으로 처리할 수 있다.

이를 통해 사실 라우팅함수에서 쓰이던 모든 콜백함수 또한 미들웨어였다는 사실을 알 수있다.

express에서는 이렇듯 미들웨어를 중심으로 동작한다. 

 

7. 미들웨어의 실행순서

미들웨어의 핵심은 req와 res라는 객체를 받아서 변형할 수 있다는 것과,  next를 통해서 다음에 실행되어야할 미들웨어를 실행할지 실행하지 않을지를 결정할 수 있다는 점이다.

또한, 경로를 통해 미들웨어가 적용될 타겟을 설정할 수 있다는 것과, get과 post등을 통해 요청 메소드에 따라 타겟을 설정할 수 있다는 점이다.

한편 위와같이 미들웨어 여러개를 콤마를 통해 붙일 수도 있다. 이렇게하면 next()가 콤마뒤에 오는 미들웨어를 실행시키게 된다. 

2개의 예제를 통해 이러한 미들웨어의 실행순서가 어떻게 활용되는지 이해할 수 있다.

위의 미들웨어는 어떤순서로 진행이 될까?

우선 특징은 get요청의 path가 같은 두개의 라우트가 있다는 것이다. 

위의 라우트의 경우 두개의 미들웨어가 들어있고, 아래의 라우트의 경우 하나의 미들웨어가 들어있다.

여기서 미들웨어의 실행순서는

1. 먼저 위치한 위의 미들웨어가 실행된다. console.log를 통해 id를 출력하고 next()를 통해 뒤이어 존재하는 미들웨어를 실행한다.

2. 콤마 뒤에 바로 위치한 User Info를 send해주는 미들웨어가 실행한다. 이때, next에 대한 내용이 없으므로, 아래의 라우트는 실행되지 않는다.

 

 

한편, 위의 경우엔 조건에 따라 다음 실행할 미들웨어를 결정한다.

1. 먼저 위치한 라우트가 실행되고 첫번째 미들웨어가 실행되는데, 이때 조건에 부합한다면 next('route')를 통해서 다음 라우트를 실행시킨다. 즉, regular를 render하는 미들웨어가 아닌 special을 render하는 다른 라우트의 미들웨어가 실행된다.

2. 조건에 부합하지않는다면 next()를 통해 뒤이어 존재하는 regular를 render하는 미들웨어를 실행시킨다. 여기서 next에 대한 내용이 따로없으므로 다음 미들웨어를 따로 실행하지 않는다.

 

8. 정적인 파일 서비스

app.use(express.static("public"));

이렇게 함으로써, public 디렉토리에서 정적인 파일을 찾을 수 있게 된다.

이후 html에서와 같이 img src에 경로를 설정하면 파일을 브라우저에 전달할 수 있게 된다.

핵심은 위와같이 정적인 파일을 찾을 디렉토리를 직접 명시해주어야 한다는 것이다.

 

 

9. 에러처리

대표적인 에러인 404에러의 경우, 코드의 끝에 아래의 코드를 입력한다.

app.use(function(req,res,next){
res.status(404).send('sorry can not find that!');
});

이때 send안의 내용은 커스터마이징 할 수 있다.

위의 코드를 코드의 끝에 두는 이유는, 미들웨어는 등록된 순서대로 순차적을로 실행되기 때문이다.

만약 이 라우트까지 도달할때까지 해당 요청에 대한 라우트를 찾지못했다면 처리가 안된 것이므로, 위와같이 에러처리를 해줄 수 있다.

 

그 외에, 에러처리가 필요한 미들웨어에서 next에 err을 넣어줌으로써 처리할 수 도 있다.

 

한편, 에러핸들링을 위한 미들웨어의 경우 (err, req, res, next)를 parameter로 갖기로 약속되어있다.

app.use(function (err, req, res, next) {
  console.log(err.stack);
  res.status(500).send("Something broke!");
});

위와 같이 에러핸들링을 위한 미들웨어를 404보다도 더 밑에 두면, next(err)를 호출한 미들웨어에서는 이 미들웨어로 순서가 넘어오게된다.

 

 

10. 라우터

작은 프로젝트의 경우 라우트가 몇개 안되지만, 프로젝트가 커질수록 라우트는 수백개에서 수천개까지 늘어날 수 있다.

이것들이 한 파일에 있는 것은 굉장히 유지보수하기 힘들뿐더러, 좋은 코딩습관이 아니다.

따라서, express는 라우터라는 것을 제공하는데 쉽게말해서, 라우트들을 분배할 수 있게 해주는 것이다.

*** 라우트들의 순서는 매우 중요하다. 요청에 맞는 라우트를 탐색하는 것은 위에서부터 순차적으로 이루어지기 때문에,

/topic/:topidId 를 갖는 라우트와   /topic/create 를 갖는 라우트의 순서에 따라 에러가 발생할수도, 안할 수도 있다.

 

라우터를 이용하면 어떠한 경로로 시작하느냐에 따라 파일을 나누어 관리하는 것이 가능하다.

라우터를 사용하는 규칙들은 다음과 같다.

1. 사용할 라우터를 불러온다. 예) const topicRouter = require('./routes/topic.js');

2. app.use를 통해 만든 라우털를 사용하도록 한다. app.use('/topic', topicRouter); 이것은 경로가 topic으로 시작하면 topicRouter를 통해 처리하겠다는 것을 의미한다.

3. topic.js에는 topic으로 시작하는 패스들을 처리할 라우트들을 위치시킨다. 

이때, const router = express.Router()로 라우터를 생성한다.

4. topic.js에서는 이 router가 app을 대신한다. 즉, router.use , router.get, router.post 등으로 사용된다.

5. topic.js에서는  module.exports= router;해주어야한다 !!

6. app.use('/topic',topicRouter)를 했다면, 해당 라우터에 도착한 요청들은 모두 경로가 topic으로 시작한다는 의미이므로, 

router.get등의 경로에는 /topic이 생략되어야한다!

 

 

11. Express-generator

Express의 프로젝트 구조는 대부분 동일하다. 

이러한 구조를 바닥부터 매번 쌓아올리는 일은 여간 지치는 일이 아니다.

Express-generator는 초기 구조를 한번에 생성해주는 편리한 도구 같은 것이다. 

사용법은 아래링크를 참고하면 좋겠다.

https://expressjs.com/ko/starter/generator.html

 

Express 애플리케이션 생성기

Express 애플리케이션 생성기 애플리케이션의 골격을 신속하게 작성하려면 애플리케이션 생성기 도구인 express를 사용하십시오. 다음의 명령을 이용해 express를 설치하십시오. $ npm install express-gener

expressjs.com

 

+) html을 view로 쓰고 싶을때

https://d2fault.github.io/2018/12/26/20181226-nodejs-html-load-with-express/

'강의 > 생활코딩' 카테고리의 다른 글

[생활코딩][WEB2] Node.js  (0) 2020.07.20
[생활코딩][WEB3] Ajax  (0) 2020.07.13
[생활코딩][WEB2] JavaScript  (0) 2020.07.08
[생활코딩][WEB2] CSS  (0) 2020.06.26
[생활코딩][WEB1] HTML & Internet  (0) 2020.06.24