Express 사용해보기

KimJH_94·2023년 1월 19일
0

NodeJS

목록 보기
3/4
post-thumbnail

Express

Express 란?

framework (공통적인 일은 프레임워크가 제작해줌 : 반제품)
Express : NodeJS에서 가장 보편적으로 사용되는 프레임워크

Express (express 사이트의 getting started에서 확인해보기)

express 설치

npm install express --save : express 설치 (node-modules 안에 express가 추가됨)

const express = require('express') const app = express() const port = 3000

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

app.listen(port, () => { console.log(Example app listening on port ${port}) })

-> 간단하게 서버 실행

기존 nodeJS에서 서버 구현할 때

response.writeHead(200); response.end(html);

response.send(html); 로 한번에 처리

express의 redirection방법

response.redirect('넘어갈 path');


상세페이지구현 (queryString을 통해 전달)

시멘틱 URL-> 주소에 쿼리스트링을 보통 숨김(/page/HTML) 여기서 가져옴
/page를 패스로 설정, /HTML을 콜백함수 안에서 가지고옴

app.get('/page/:pageId', function(request, response){ response.send(request.params); });

패스 : /page/:pageId
-> /page/1 로 주소를 검색할 때 request.params = {pageId : 1}; 로 받아올 수 있음
-> 쿼리 스트링이 아닌 패스방식을 통해서 주소 전달하는 라우팅 기법


미들웨어

미들웨어 - 바디파서

third party middleware (남들이 만든 미들 웨어)
그 중에서 body-parser 사용해보기

기존에는 바디 변수를 정의하고, 데이터가 도착할 때 마다 바디 변수에 추가하여 데이터가 없다는 이벤트가 발생했을 때, 그 바디 변수를 담아주는 형식으로 처리했음 이걸 바디파서를 이용하여 문제를 해결하게 됨

  1. 바디파서 설치
    npm install body-parser —save

  2. 바디파서 모듈 로드

var bodyParser = require('body-parser');
  1. 명령문 추가
// form데이터는 이렇게 처리
app.use(bodyParser.urlencoded({ extended: false })); 

// json으로 처리할 땐 이렇게 처리
app.use(bodyparser.json())
  1. 이제 post로 받은 데이터에 대해서, 콜백 함수에 request 에 담겨있는 정보를 request.body.{받은 데이터의 name}으로 가져올 수 있음
// bodyParser 사용 (폼 데이터 형식 처리)
// bodyParser가 만들어내는 미들웨어를 표현하는 표현식
// 1. 사용자가 요청할 때 마다 바디파서 미들웨어가 실행 됨 
// 2. post 데이터를 내부적으로 분석해서 가져온 다음에 콜백을 호출하도록 약속
// 3. 콜백의 request.body 프로퍼티를 만들어줌

// form데이터는 이렇게 처리
app.use(bodyParser.urlencoded({ extended: false })); 

// json으로 처리할 땐
// app.use(bodyparser.json())



// 전체 app에서 readdir 기능이 공통적으로 사용이 된다! (글 목록을 표현해주는 기능)
// 이 기능을 미들웨어로서 처리!
// 모든 코드에서 (모든 라우트에서) request.list를 통해 filelist에 접근 가능하다!
// 하지만 post상황에선 굳이 filelist를 불러올 필요가 없음
// app.use -> app.get으로 바꾸고, get 방식으로 들어오는 모든 요청에 readdir을 받아올 수 있도록 해줌
// 결론 : function(){} 이게 readdir기능을 하는 미들웨어이다. 이것 처럼 express에서는 모든 라우터의 콜백함수는 전부 미들웨어 기능을 하는 것
app.get('*', function(request, response, next){
  fs.readdir('./data', function(error, filelist){
    request.list = filelist;
    // next() 엔 그 다음에 호출되어야 할 미들웨어가 담겨있음
    next();    
  });
})

미들웨어 - compression

  • 페이지의 데이터 용량이 너무 많으면 비용이 많이 나오게 됨
  • 압축을 통해 비용을 줄이자
  • 웹서버가 웹브라우저한테 응답할 때, 데이터를 압축해서 보냄 + 이 응답은 ~~ 방식으로 압축했으니 ~~이렇게 푸세요 라고 브라우저한테 알려줌
  • 브라우저는 압축된 데이터를 받아 서버가 알려준대로 풀게 됨 (물론 압축을 하고 푸는 비용도 필요하지만, 이게 훨씬 저렴하다)

npm install compression --save
app.use(compression());


미들웨어 제작

// 전체 app에서 readdir 기능이 공통적으로 사용이 된다! (글 목록을 표현해주는 기능)
// 이 기능을 미들웨어로서 처리!
// 모든 코드에서 (모든 라우트에서) request.list를 통해 filelist에 접근 가능하다!
// 하지만 post상황에선 굳이 filelist를 불러올 필요가 없음
// app.use -> app.get으로 바꾸고, get 방식으로 들어오는 모든 요청에 readdir을 받아올 수 있도록 해줌
// 결론 : function(){} 이게 readdir기능을 하는 미들웨어이다. 이것 처럼 express에서는 모든 라우터의 콜백함수는 전부 미들웨어 기능을 하는 것

app.get('*', function(request, response, next){
  fs.readdir('./data', function(error, filelist){
    request.list = filelist;
    // next() 엔 그 다음에 호출되어야 할 미들웨어가 담겨있음
    next();    
  });
});

app.get('/', function(request, response){
    var title = 'Welcome';
    var description = 'Hello, Node.js';
  	//  여기서 request.list로 filelist를 대신하여 사용
    var list = template.list(request.list); 
    var html = template.HTML(title, list,
      `<h2>${title}</h2>${description}`,
      `<a href="/create">create</a>`
    );
    response.send(html);
});

미들웨어 실행순서

애플리케이션 레벨의 미들웨어

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

// req, res 변수를 받고 next를 통해 다음 미들웨어를 실행할지 안할지를 이전 미들웨어가 결정하도록 한다.
app.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

// 특정 경로만 미들웨어가 동작하도록 할 수 있음
app.use('/user/:id', (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

// get 방식인 경우에만 동작하도록 할 수 있음
app.get('/user/:id', (req, res, next) => {
  res.send('USER')
})

// 여러개의 함수를 미들웨어로 등록할 수 있음
app.use('/user/:id', (req, res, next) => {
  console.log('Request URL:', req.originalUrl)
  next()
}, (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

// 똑같은 패스를 가진 라우트의 경우 next가 실행되면 다음 미들웨어 호출
// next 가 없으면 하나의 미들웨어만 실행되고 끝남
app.get('/user/:id', (req, res, next) => {
  console.log('ID:', req.params.id)
  next()
}, (req, res, next) => {
  res.send('User Info')
})
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', (req, res, next) => {
  res.send(req.params.id)
})

// 조건문을 통해 다음 미들웨어가 실행될지 안될지를 정할 수 도 있음
app.get('/user/:id', (req, res, next) => {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, (req, res, next) => {
  // send a regular response
  res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', (req, res, next) => {
  res.send('special')
})

정적인 파일의 서비스 (이미지, 자바스크립트, CSS)

app.use(express.static('public')); // static 파일 찾아오는 모듈

이제 주소에 localhost:3000/images/hello.jpg 로 검색하면 해당 파일을 볼 수 있음 (images/hello.jpg는 파일의 경로)

원하는 이미지를 <img src = "images/hello.jpg"> 로 url을 통해서 접근할 수 있다.


에러처리

app.get('/page/:pageId', function(request, response, next){
  var filteredId = path.parse(request.params.pageId).base;
  fs.readFile(`./data/${filteredId}`, 'utf8', function(err, description){
    if(err){  // 만약 에러가 있다면 다음 미들웨어로 에러를 나타내주기
     next(err); // 이 때 맨 밑에 설정한 500에러에서 발생하는 미들웨어가 실행됨
    } else{ // 에러가 없다면 원래 짜놓은 코드실행
      var title = request.params.pageId;
      var sanitizedTitle = sanitizeHtml(title);
      var sanitizedDescription = sanitizeHtml(description, {
        allowedTags:['h1']
      });
      var list = template.list(request.list);
      var html = template.HTML(sanitizedTitle, list,
        `<h2>${sanitizedTitle}</h2>${sanitizedDescription}`,
        ` <a href="/create">create</a>
          <a href="/update/${sanitizedTitle}">update</a>
          <form action="/delete_process" method="post">
            <input type="hidden" name="id" value="${sanitizedTitle}">
            <input type="submit" value="delete">
          </form>`
      );
      response.send(html);
    }
  });
});

404 에러처리

app.use((req, res, next) => {
  res.status(404).send("Sorry can't find that!")
})

500 에러 처리 핸들링

// 에러를 핸들링 하기위한 미들웨어 
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

라우터 파일로 분리

라우터 페이지

const express = require('express');
const router = express.Router();
// 필요한 모듈들 main에서 가져와서 추가해주기
// template과 같이 경로가 들어간 모듈은 경로 다시 수정해서 잡아주기

// main 페이지에서 app.use('/topic') 으로 경로를 잡아줬기 때문에
// 라우터에선 앞에 topic을 빼줘야한다(안그러면 /topic/topic/create로가야함)
router.get('/create', (req, res)=>{
  ...
})
router.post()

// router export시켜서 메인에서 써먹을 수 있도록
model.exports = router; 

main 페이지

const express = require('express') 
const app = express()
// 라우터에서만 쓰이는 모듈은 삭제해주기

const indexRouter = require('./routes/index');
// topic 파일 모듈로 로드
const topicRouter = require('./routes/topic'); 


// /topic라고 시작하는 주소들에게 topicRouter라는 미들웨어를 적용하겠다는 뜻
app.use('/', indexRounter);
app.use('/topic', topicRouter);

보안관련

  • express 최신화
  • https 사용
  • helmet 사용 (기본적으로 킨다고 생각하기)
    - npm install --save helmet
    const helmet = require('helmet');
    app.use(helmet());
  • cookie
  • dependency 안전하게 관리하기
    - 디펜던시 중에는 취약점을 가진 것들이 있으니까 주의해야 함
    - sudo npm i nsp -g
    • nsp check

    express generator

  • sudo npm install -g express-generator
  • express myapp : myapp이라는 프로젝트 생성
  • cd myapp -> npm install : myapp 안의 package.json 디펜던시 설치
  • npm start : 시작하는 법 (package.json 에 start 아래 항목을 수정하여 변경 가능)
profile
안녕하세요.

0개의 댓글