일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 자바스크립트
- execution context
- 코드스테이츠
- 운영체제
- 자바
- 자료구조
- java
- 컴퓨터공학
- 글또
- python algorithm
- node.js
- algorithm
- 프로그래머스
- 알고리즘
- 파이썬
- REACT
- react 기초
- Computer Science
- 개발공부
- OS
- 파이썬 알고리즘 인터뷰
- Zerobase
- 비동기
- context switching
- useState
- Operating System
- typeScript
- Python
- codestates
- JavaScript
- Today
- Total
Back to the Basics
[Web Server][Express]- Middleware 기초 - Writing Middleware for use in Express App 본문
[Web Server][Express]- Middleware 기초 - Writing Middleware for use in Express App
9Jaeng 2021. 11. 5. 19:38Middleware
Express Middleware 기초적인 사용을 위해 작성한 code 분석 , method 공부 , 개념 공부 포스팅
Express 공식문서의 Writinf middleware for use in Express apps을 참고하였습니다.
- Middleware function Middleware 함수는 request object, response object , request-response 주기에서 next 함수에 대한 권한을 갖는 함수이다.
- next function : Express router에서 현재 middleware 다음에 실행 될 middleware 함수를 실행한다.
- Middleware 함수는 아래의 작업들을 수행한다.
- 모든 code를 실행한다.
- 요청,응답 객체에 대한 변경을 실행한다.
- 요청 - 응답 cycle을 종료한다.
- stack 내의 다음 middleware를 호출한다. 현재의 middleware req-rsp cycle이 종료되지 않는 경우 next() 메서드를 호출하여 다음의 middleware 함수로 control을 전달해야 한다.
/* Express middleware를 이하 위한 기초 연습
1. 모든 요청에 대해 url이나 메소드를 확인할 때 use()
2. 요청 헤더에 사용자 인증 정보다 담겨있는지 확인할 때
*/
const express = require("express");
const app = express();
const mylogger = function (req, res, next) {
console.log(`http request is ${req.method}, url is ${req.url}`);
next();
};
// use()를 사용하면 routing 전에 미들웨어 함수를 로드한다.
app.use(mylogger); // 모든 요청에 mylogger middleware를 적용한다.
app.use((req, res, next) => {
// token이 있는 경우에만 허용
if (req.headers.token) {
req.isLoggedIn = true;
next();
} else {
res.status(400).send("invalid user");
}
});
app.get("/", function (req, res) {
res.send("Heelo World!");
});
app.listen(3000);
- next() 메서드를 middlewae 함수 내부에서 호출하면, 앱 내의 다름 미들웨어 함수가 호출된다.
const mylogger = function (req, res, next) {
console.log(`http request is ${req.method}, url is ${req.url}`);
next();
};
- use() 메서드를 사용하면 모든 request에 적용된다.아래와 같은 코드를 작성하면, app이 요청을 수신할 때마다 use로 호출한 middleware 함수가 호출된다.
// use()를 사용하면 routing 전에 미들웨어 함수를 로드한다.
app.use(mylogger); // 모든 요청에 mylogger middleware를 적용한다.
app.use((req, res, next) => {
// token이 있는 경우에만 허용
if (req.headers.token) {
req.isLoggedIn = true;
next();
} else {
res.status(400).send("invalid user");
}
});
- middleware는 먼저 로드된 middleware 함수가 먼저 실행된다. 만약 use()를 사용한 middleware가 루트 경로에 대한 라우팅 이후에 로드되면, 루트 경로의 route handler가 request- response cycle을 종료하기 때문에 use() 메서드를 사용한 middleware는 실행되지 않는다. middleware function은 stack에 있는 middleware 함수에 request를 전달한다.
app.use(mylogger); // 모든 요청에 mylogger middleware를 적용한다.
app.use((req, res, next) => {
// token이 있는 경우에만 허용
if (req.headers.token) {
req.isLoggedIn = true;
next();
} else {
res.status(400).send("invalid user");
}
});
app.get("/", function (req, res) {
res.send("Heelo World!");
});
실습
- requestTime 이라는 middleware function을 만들고 사용해보는 예제 (공식문서 예제)
/*
Express - Middleware - Create requestTime
- requestTime middleware 함수를 만들고 request object에 requestTime이라는 property를 추가한다.
- requestTime middleware는 현재의 시각을 request.requestTime property에 할당한다.
- root 경로의 route의 callback 함수는 이 middleware 함수가 request에 추가하는 특성을 사용한다.
*/
const express = require("express");
const app = express();
let requestTime = function (req, res, next) {
req.requestTime = Date.now();
next();
};
app.use(requestTime);
app.get("/", function (req, res) {
let responseText = "Hello Sora!<br>";
responseText += `<small>Request at: ` + req.requestTime + `</small>`;
res.send(responseText);
});
app.listen(3000);
위의 앱은 요청을 실행할 때, 요청의 timestemp를 브라우저에 표시한다.
자주 사용하는 미들웨어
위의 개념을 사용하여 middleware function의 사용을 확인.
- 미들웨어를 사용하는 상황
- 모든 요청에 대해 url 또는 method확인
- body(payload)를 구조화할 때
- 모든 req/res에 CORS header를 추가할 때
- request header에 사용자 인증 정보가 담겨있는지 확인할 때
- 모든 요청에 대해 URL , Method 확인
middleware function의 인자인 req, res를 사용하여 method, url 등의 정보를 쉽게 출력할 수 있다.
const myLogger=function(req,res,next){
console.log(req.method, req.url)
};
app.use(myLogger);
app.get('/',function(req,res){
res.send('Hello sora!')
});
app.listen(3000);
- body(payload) 구조화
HTTP body를 node.js로 받을 때에는 아래와 같이 chunk를 합치고, buffer를 string으로 변환하는 작업으로, 다소 복잡한 방식으로 body를 얻었다.
let body=[]
request.on('data',(chunk)=>{
body.push(chunk);
}).on('end',()=>{
body=Buffer.concat(body).toString();
});
하지만, body-parser middlewaer를 사용하면 간단하게 구현이 가능하다.
const bodyParser=require('body-parser')
const jsonParser=bodyParser.json()
app.post('/api/users',jsonParser,function(req,res){
// JSON type으로 req.body에 payload가 담겨져있다.
})
만약 body-parser를 사용하지 않고 아래와 같이 express로 post 요청을 처리한다면 req.body는 undefined 이기 때문에 undefined error를 마주친다.
app.post('/',function(req,res){
console.log(req.body)
})
// Undefined Error !
body-parser 문서를 참고.
body-parser는 node.js 모듈이다. client의 post 요청의 body로부터 prameter를 편리하게 추출한다.
- bodyParser.json([options])
- 오직 json만 parse 하고 Content-Type header가 type option과 일치하는 요청만 확인하는 middleware를 반환한다. (Content-type이 application/json 방식인 경우만 받아준다)
- middleware 이후에 parse 된 data를 포함한 body 객체가 request 객체에 포함된다.
- 모든 req-res에 CORS header를 붙일 때
node.js 에서는 아래와 같이 writeHead method를 사용해야 하고, OPTION 메서드에 대한 routing을 따로 구현해야 하며 매번 Access-Control-Allow-* header를 정의해야 한다.
// 매번 이런 header를 작성해야한다
const corsHeader={
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
'Access-Constol-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10
};
// OPTIONS에 대한 routing을 작성해야한다.
if(req.method==='OPTIONS'){
res.writeHead(201,corsHeader);
res.end()
}
하지만 cors middleware를 사용하면 이 또한 간단하게 처리할 수 있다.
const cors=require('cors')
// 생략
app.use(cors()) // 모든 요청에 대해 CORS를 허용
또한, 특정 요청에만 cors 모듈을 적용할 수도 있다.
const express=require('express')
const cors=require('cors')
const app=express()
app.option('/goods/:id',cors())
// Delete 요청에 대해 pre-flight 요청을 활성화한다.
app.del('//goods/:id',cors(),function(req,res,end){
res.json({msg: 'This is CORS-enabled for all origin'})
})
app.listen(80,function(){
console.log('CORS-enabled web server listening on port 80')
})
// 아래와 같이 전면적으로 pre-flight을 적용할 수도 있다.
app.options('*',cors())
- corscors는 node.js 다양한 options CORS를 활성화제 사용할 수 있는 Connect / Express middleware를 제공하는 package이다.
- Enabling CORS Pre - Flightpre-flight이 가능하려면 , OPTIONS handler를 route 해야 한다.
const express=require('express')
const cors=require('cors')
const app=express()
app.option('/goods/:id',cors())
// Delete 요청에 대해 pre-flight 요청을 활성화한다.
app.del('//goods/:id',cors(),function(req,res,end){
res.json({msg: 'This is CORS-enabled for all origin'})
})
app.listen(80,function(){
console.log('CORS-enabled web server listening on port 80')
})
// 아래와 같이 전면적으로 pre-flight을 적용할 수도 있다.
app.options('*',cors())
- Configuring CORS Asynchronously
var express = require('express')
var cors = require('cors')
var app = express()
var allowlist = ['http://example1.com', 'http://example2.com']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (allowlist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true }
// reflect (enable) the requested origin in the CORS response
} else {
corsOptions = { origin: false }
// disable CORS for this request
}
callback(null, corsOptions)
// callback expects two parameters: error and options
}
app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for an allowed domain.'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
- 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
HTTP request에서 token의 여부를 판단하고, 이미 로그인되었다면 성공을 아니라면 error를 보내는 middleware 예시이다.
app.use((req,res,next)=>{
if(req.headers.token){
req.isLoggedIn=true;
next()
}else{
res.status(400).send('invalid user')
}
})