ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ExpressJS - express.js 서버 시작하기(setting, 미들웨어)
    FrameWork/Express.js 2024. 3. 18. 15:55

    express.js 서버 시작하기 

    ExpressJS로 HTML 서빙하기

    index.html

    <!DOCTYPE html>
    <html lang="ko">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>익스프레스 서버</title>
    </head>
    <body>
        <h1>익스프레스</h1>
        <p>배워봅시다.</p>
    </body>
    </html>

     

    app.js

    const express = require('express');
    
    const app = express();
    
    // 서버에 port라는 변수를 심는다.
    // 전역 변수의 개념 
    app.set('port',process.env.PORT||3400);
    
    app.get('/',(req, res) => {
        res.sendFile('./index.html');
    });
    
    app.listen(app.get('port'),() => {
        console.log(app.get('port'),'번 포트에서 대기 중')
    });

     

    sendFile() 메서드를 사용하면 express에서 알아서 fs 패키지를 사용해서 './index.html' 경로에 있는 파일을 불러온다. 

     

    app.js

    const express = require('express');
    const path = require('path');
    
    const app = express();
    
    // 서버에 port라는 변수를 심는다.
    // 전역 변수의 개념 
    app.set('port',process.env.PORT||3400);
    
    app.get('/',(req, res) => {
        res.sendFile(path.join(__dirname,'index.html'));
    });
    
    app.listen(app.get('port'),() => {
        console.log(app.get('port'),'번 포트에서 대기 중')
    });

     

    하지만 경로를 처리할 때는 조금더 확실하게 하기 위해서 path 모듈을 사용하면 좋다. 

     

     

    html, js 소스코드 변경에 따른 감지

     

    app.js

    app.get('/',(req, res) => {
        res.sendFile(path.join(__dirname,'index.html'));
    });

     

    • http://localhost:4500

    위 와 같은 index URL을 호출할 때 서버를 실행시킬 경우는  res.sendFile() 메서드 가  그때 마다 index.html 파일을 동적으로 일어온다. html 파일은 변동사항을 적용해 준다. 하지만 app.js 파일은 소스코드를 변경해도 node에서 한번 소스코드의 내용을 cache하고 있는 파일을 사용하고 있기 때문에 require('cache')직접 지워주지 않는이상  이상 소스코드 변경 사항이 바로 적용되지 않는다. 

     

    하지만 require('cache')를 직접 지우는 것은 다른 중요한 캐시 정보를 지울 위험이 있기 때문에 서버를 한번 껐다가 키는 방식으로 소스코드 변경 사항을 적용해준다. (이때 chache된 메모리가 날아간다.) 하지만 nodemon을 사용하면 코드에 변화에 따라 서버를 알아서 재시작해준다. 

     


    미들웨어 사용하기

     

    1.

    app.get('/',(req, res) => {
        res.sendFile(path.join(__dirname,'index.html'));
    });
    
    app.post('/',(req,res) =>{
        res.send('hello express');
    });
    
    app.get('/about',(req,res) => {
        res.send('hello express');
    })

     

    위 코드와 같이 주소를 나누어서 처리하면 코드가 깔끔해지는 장점이 있는 반면에 단점도 존재한다. 

     

    2.

    app.get('/',(req, res) => {
        console.log('모든 요청에 실행하고 싶어요');
        res.sendFile(path.join(__dirname,'index.html'));
    });
    
    app.post('/',(req,res) =>{
        console.log('모든 요청에 실행하고 싶어요');
        res.send('hello express');
    });
    
    app.get('/about',(req,res) => {
        console.log('모든 요청에 실행하고 싶어요');
        res.send('hello express');
    })

     

    위 코드 같이 모든 API에 처리하고 싶은 공통적인 기능이 존재한다고 가능하면 특정 URL을 처리하는 라우터마다 동일한 코드를 작성해 주어야 하는 중복이 발생한다. 이런 중복을 제거하기 위해서 미들웨어라는 개념이 생겨났다. 

     

    3.

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

     

     

    미들웨어를 사용하기 위해서는 app.use() 메서드를 사용하면 된다. app.use() 메서드의 정의된 로직은 모든 라우터에 실행이된다. 

     

    4.

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

     

    하지만 app.use()메서드를 사용해서 모든 라우터에 use()메서드 안에 로직을 실행시킬 수 있는 것이 아니라. 위 코드와 같이 next()메서들 인자로 받은뒤 use()메서드의 콜백함수에서 next()를 실행 해주어야 다음 라운터 중에 일치하는 것에 찾아간다. 

     

    그래서 express 코드는 위에서 부터 아래까지 코드가 순차적으로 실행 되지만, app.user()메서드를 사용한 미들웨어의 경우는 next()메서드를 로직안에서 실행 시켜주어야지 다음 순서에 올 메서드를 실행 시켜준다.

     


    와일드 카드 성격을 가진 URL

     

    라우트 매개변수(req.params)

    app.get('/category/:name',(req, res) =>{
    	res.send(`매개변수 name= ${req.params.name}를 받았습니다.`);
    });
    
    app.get('/category/javascript',(req, res) =>{
    	res.send('category javascript URL 입니다.');
    });

     

    express.js 코드가 라우터 코드가 위에서 아래로 실행된다는것이 중요한 이유가  라운터에 매칭된 URL 중에 와일트 카드 성격을 띈 라우트 매개변수가 포함될 수 있기 때문이다.  이때 위 코드와 같이 'category/javascript' URL 라우터가 'category/:name' 위에 위치하게 되면 아무리 URL 'category/javascript'  API를 부를 려고해도 'category/:name' 이 호출되면서 javascript는 라우트 매개변수 처리된다.  그래서 라우트 매개변수를 가진 라우터는 동일한 prefix URL을 가진 것 중에 제일 앞부분에 위치해야 한다.

     

     

    에스터리스코(asterisko) URL

    app.get('*',(req, res) =>{
    	res.send('모든 get 요청에 응답하는 라우터 입니다.');
    });

     

    위 코드와 같이 라우터에 URL 값을 넣는 곳에 "*" 즉 에스터리스코(asterisko)를 넣으면 모든 get 요청에 대해 응답하는 라우터로 사용하겠다는 의미가 된다. 

     

    위와 같이 설정된 라우터가 express 코드에서 최상단에 위치할 경우에는 이 코드 밑에 어떤 GET URL 과 매핑된 라우터가 있어도 모든 GET  request를 위 에스터리스코를 가진 get라우터가 빨아들이게된다.  

     

     

    따라서 와일드 카드 성격을 가진 라우터는 소스코드의 가장 하단에 배치해야한다.

     


    미들웨어 특성 이해하기

    함수가 미들웨어이다.

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

     

    엄밀히 말하면 app.user()메서드 자체가 미들웨어가 아니라 해당 메서드에 들어가는 콜백 함수가 미들웨어이다. 

     

     

    미들웨어는 특정 메서드에 장착되는 것

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

     

    더 자세히 말하면 위 와 같이 app.get()메서드에 들어간 callback 함수도 미들웨어이다. 즉 어떤 app.메서드에 콜백 함수로장착되는지에 따라 미드웨어가어떻게 쓰일지가 결정되는 것이다. 

     

     

    app.use()와 URL

    app.use((req,res,next) => {
        console.log('모든 요청에 실행하고 싶어요');
        next();
    });
    
    app.use('/about',(req,res,next) => {
        console.log('/about 으로 시작하는 URL에 실행됩니다.');
        next();
    });
    
    app.get('/',(req, res) => {
        res.sendFile(path.join(__dirname,'index.html'));
    });
    
    
    app.get('/about',(req,res) => {
        res.send('hello express');
    });

     

    추가적으로 app.use()메서드로 app.get()과 같은 메서드와 같이 어떤 URL을 가진 경우에만 실행되도록 설정할 수 있다.

     

     

    app.use메서드와 여러개의 미들웨어 

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

     

    미들웨어를 여러개 동시에 넣어주어도 된다. 그러면 여러개의 미들웨어 역시 위에서 아래도 순서대로 실행되기 때문에  위코드에서도 미들웨어가 장착된 순서대로 실행된다. 

     

     

    Error 처리 

     

    서버는 비동기이고 Node.js는 싱글쓰레드 이기 때문에 Error 처리에 민감해야 한다. 즉 Error 처리를 잘해야지 서버가 죽지 않고 잘 돌아 간다. 

    // 1.app.set() app에 관련된 설정
    
    // 2.app.use() 공통미들웨어
    
    // 3.URL에 대한 라우터
    
    // 4.Error에 대한 미들웨어
    app.use((err, req, res, next )=>{
        console.error(err);
        res.send("에러가 발생하였습니다.");
    });

     

    Error가 났을 경우 서버에서 보고 하는 Error 로그를 그대로 반환하지 않고, 직접 Error처리를 한다. 이런 Error처리도 미들웨어로 할 수 있다. Error 처리를 하는 미들웨어는 1) app.use()메서드를 사용하고, 에러 미들웨어는 특이한 점이 2)파라미터를 err로 첫번 째로 받는다. 그리고 3)에러 미들웨어 같은 경우는 err, req, res, next  파라미터 4개를 모두 받아야 한다.

     

     

    404에러에 대한 처리

    // 1.app.set() app에 관련된 설정
    
    // 2.app.use() 공통미들웨어
    
    // 3-1.URL에 대한 라우터
    
    app.use((req,res,next)=>{
        res.send('404 에러입니다.');
    })
    
    // 4.Error에 대한 미들웨어
    app.use((err, req, res, next )=>{
        console.error(err);
        res.send("에러가 발생하였습니다.");
    });

     

    URL을 처리하는 라우터의 제일 밑 그리고 전역을 Error를 처리하는 app.user()메서드 바로위에 404 에러에대한 처리를 하는 미들웨어를 위치 시킨다.

     

    전역의 error를 처리하는 미들웨어는 서버에서 발생한 error만을 받아서 처리한다. 추가로 401,403,409이런 에러는 혹은 500번대 에러는 서버를 해킹하려는 해커들에게 특정 URL에대한 취약점을 노출시킬 수 있기 때문에 사용하는 것에 주의를 기울여야 한다.

     

     

    [출처 - [개정3판]Node.js 교과서 - 기본부터 프로젝트 실습까지, 저 조현영]

    https://www.inflearn.com/course/%EB%85%B8%EB%93%9C-js-%EA%B5%90%EA%B3%BC%EC%84%9C

     

    [개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지 강의 - 인프런

    노드가 무엇인지부터, 자바스크립트 최신 문법, 노드의 API, npm, 모듈 시스템, 데이터베이스, 테스팅 등을 배우고 5가지 실전 예제로 프로젝트를 만들어 나갑니다. 클라우드에 서비스를 배포해보

    www.inflearn.com

     

    댓글

Designed by Tistory.