오늘도 개발

Middleware 본문

웹 프로그래밍/Javascript

Middleware

Sueeeeeee 2022. 9. 28. 17:52

1. Middleware란?

출처 - [저스트코드] Middleware가 무엇인가요?

API는 요청을 받았을 때부터 응답을 내보낼 때 까지 여러 과정을 단계적으로 실행한다.

한 과정에서 다음 과정으로 넘어갈 때 거쳐야 하는 함수를 미들웨어라고 한다.

미들웨어는 다음 과정으로 넘어가게 해줄 수도 있고, 넘어가면 안 되는 상황에선 막기도 한다.

 

위 그림에 있는 다섯개의 사각형이 모두 미들웨어이다.

express를 사용하면 express가 제공하는 미들웨어를 사용할 수 있다.

 

미들웨어를 사용하면 관심사를 분리할 수 있다. 즉, 유지 보수가 쉽다.

코드 중복을 줄일 수도 있다.

 

2. 사용 예시

1) req.body 추가(app.use(express.json())

포스트맨에서 post 요청을 보낼 때 body에 raw-json으로 값을 보내면 원래 string으로 받게 된다.

http는 모든 값을 string으로 전송하기 때문이다.

이 값을 사용하려면 다시 json으로 변환해야 하는데 매번 이렇게 하기는 번거롭다.

그래서 express는 req.body 값을 json으로 변환해주는 미들웨어를 제공한다.

이 미들웨어는 자동으로 요청값을 json으로 변환해준다.

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

// 옳지 않은 방식
// 라우터 함수를 미들웨어 선언 전에 작성하면 적용이 안 됨 
app.post('/bad', (req, res ,next) => {
    console.log(req.body); // undefined
    res.json({message : 'bad'});
})

// 올바른 방식
// req.body를 json으로 바꿔주는 express 미들웨어 등록
app.use(express.json());

// 미들웨어가 모든 라우터 함수에 적용됨
app.post('/', (req, res, next) => {
    console.log(req.body)
    res.json({message:'root'})
})

app.post('/ex', (req, res, next) => {
    console.log(req.body)
    res.json({message: 'ex'})
})

app.listen(8000)

 

2) 인증, 인가

미들웨어를 직접 만들어서 인증, 인가를 진행할 수 있다. 

인증/인가가 필요한 api 앞에 미들웨어를 두어 

인증/인가 미들웨어를 통과한 api만 끝까지 실행되도록 만들면 편리하다.

 

<인증, 인가가 필요한 라우터에만 미들웨어를 두는 경우>

const http = require('http')
const express = require('express');
const app = express()
app.use(express.json())

async function authMiddleware(req, res, next){
    const token = req.headers.authorization;
    if (!token){
        res.status(400).json({message: 'Invalid token'})
        return;
    }    
    if (token === '123'){ // 토큰이 일치하는 경우
        req.token = token; // 다음 미들웨어에서 req 값 열어보면 userInfo가 추가되어 있음
        next(); // 다음 미들웨어/엔드포인트로 넘어감
    } else { // 로그인 실패 시
        // 응답 보내기
        res.status(400).json({message : 'failed to login'})
    }
}

const login = (req, res) => {
    console.log(req.token) 
    res.status(200).json({message: 'login success'})
}

const ex = (req, res) => {
    res.status(200).json({message: 'ex success'})
}

// 로그인 필요한 라우터에만 미들웨어 추가
app.post('/login', authMiddleware, login)
app.post('/ex', ex)

app.listen(8000, () => {
    console.log('listening at 8000')
})

 

<모든 라우터에 미들웨어를 추가하는 경우>

const http = require('http')
const express = require('express');
const app = express();
// 모든 라우터에 적용할 미들웨어 등록
app.use(express.json(), authMiddleware);

async function authMiddleware(req, res, next){
    const token = req.headers.authorization;
    if (!token){
        res.status(400).json({message: 'Invalid token'})
        return;
    }    
    if (token === '123'){ // 토큰이 일치하는 경우
        req.token = token; // 다음 미들웨어에서 req 값 열어보면 userInfo가 추가되어 있음
        next(); // 다음 미들웨어/엔드포인트로 넘어감
    } else { // 로그인 실패 시
        // 응답 보내기
        res.status(400).json({message : 'failed to login'})
    }
}

const login = (req, res) => {
    console.log(req.token) 
    res.status(200).json({message: 'login success'})
}

const ex = (req, res) => {
    console.log(req.token) // 토큰 출력됨
    res.status(200).json({message: 'ex success'})
}

app.post('/login', login)
app.post('/ex', ex)

app.listen(8000, () => {
    console.log('listening at 8000')
})

 

3) CORS

CORS는 브라우저의 보안 정책. 어떤 서버의 자원을 가져올 때 같은 origin에서 접근해야 한다는 것.

따라서 브라우저에게 해당 서버는 모든 요청에 열려있다는 것을 알려야 하는데, 이 때 미들웨어를 사용하면 편리하다.

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

// 1. CORS 사용하지 않으면 전체 거부
// 2. 경로 명시하면 해당 경로만 인정 
// app.use(cors({ origin: "sue-is-programming.com" }));
// 3. 경로 명시하지 않으면 모든 경로 인정
app.use(cors()); 

app.listen(8000)