Lsiron

미들웨어??? 본문

백엔드/Node.js

미들웨어???

Lsiron 2024. 6. 10. 12:00

미들웨어 란?

자바스크립트 미들웨어는 웹 애플리케이션에서 요청과 응답 사이에 위치하여 중간에 서비스를 제공하거나 요청을 처리하는 소프트웨어 구성 요소이다.

 

이는 요청과 응답의 흐름을 관리하고 조작할 수 있는 유연한 방법을 제공하여 애플리케이션의 동작을 수정하거나 보완하는 데 사용된다.

 

주로 웹 개발에서는 서버 측 미들웨어와 클라이언트 측 미들웨어로 구분된다.

 

서버 측 미들웨어는 클라이언트의 요청을 받아 처리하기 전에 실행되며, 보통은 라우팅, 인증, 로깅, 데이터 변환 등의 작업을 처리한다. 반면 클라이언트 측 미들웨어는 브라우저에서 애플리케이션에 필요한 추가적인 동작을 처리하기 위해 사용된다.

 

공항으로 비유를 해보자.

승객은 클라이언트,. 미들웨어는 보안검색대 , 비행기가 서버이다.

승객이 비행기에 탑승 하려면 보안검색대는 승객이 비행기에 탑승하기에 적합한지 검사를 할 것이다.

이렇게 미들웨어는 클라이언트 요청이 서버로 전달되기 전에 중간에서 요청을 처리하고, 필요한 작업을 수행한다.

이는 보안검색대가 승객을 처리하는 과정과 유사하게, 미들웨어는 클라이언트의 요청에 대해 처리하는 과정을 중간에서 캡처하고 수정할 수 있다.

 

 

코드 예시를 들어가면서 살펴보자!

 

app.get('/', (req, res) => {
    if(!req.user){
        res.send('cannot login')
    }
    res.send('success login')
})

app.get('/login', (req, res) => {
    if(!req.user){
        res.send('cannot login')
    }
    res.send('success login')
})

 

=> 위 코드에서 로그인을 검사하는 if 조건문이 반복됨을 알 수 있다.

먼저 이러한 반복문을 번거롭게 반복하지 않도록 하기위해 우리는 함수를 이용할 수 있다.

 

const login = (req, res) => {
    if(!req.user){
        res.send('cannot login')
    }
}

app.get('/', (req, res) => {
    login(req, res);
    res.send('success login')
})

app.get('/login', (req, res) => {
    login(req, res);
    res.send('success login')
})

 

=> 번거롭게 반복하던 반복문을 함수를 이용하여 간단하게 사용할 수 있도록 변경 해 주었다.

이제 미들웨어를 사용하는 방식으로 바꾸어 보자. 그러면 우리는 다음과 같이 바꿀 수 있다.

 

const login = (req, res) => {
    if(!req.user){
        res.send('cannot login')
    }
}

app.get('/', login ,(req, res) => {
    res.send('success login')
})

app.get('/login', login ,(req, res) => {
    res.send('success login')
})

 

=> 그러면 login 함수는 해당 API 의 요청과 응답 사이에서 실행이 된다.

 

즉, 저 사이에서 클라이언트를 검사 하는 것이다. 단, 한 가지 더 넣어주어야 할 것이 있다.

(참고로 미들웨어 자리(login 자리)에는 변수를 쓰지 않고도  함수를 직접 넣을 수 있다.)

 

const login = (req, res, next) => {
    if(!req.user){
        res.send('cannot login')
    }
    next()
}

app.get('/', login ,(req, res) => {
    res.send('success login')
})

app.get('/login', login ,(req, res) => {
    res.send('success login')
})

 

=> 바로 login 함수를 선언한 파라미터에 next 인자를 추가로 넣어주고, 내부에 next() 함수를 추가 해야한다.

이로써 완벽한 미들웨어 라고 할  수 있다. 

 

(주의할 점: 만약 미들웨어 함수 내부에서 if 조건문에 있는 res.send('cannot login') 말고도 밑에 추가로 response를 넣었을 경우, res.send('cannot login') 응답이 먼저 실행되면 그 밑에 있는 코드는 next() 제외하곤 실행되지 않는다.

 

최종적으로,  해당 서버로 URL 요청이 들어오면 login 함수가 먼저 실행이 되고, 검사를 통과하면, res.send('success login') 이 실행된다.

 

미들웨어 함수 내부 또한 API 내부에서 요청과 응답을 자유롭게 사용가능 했던 것과 같이 기능개발을 할 수 있다. 

예를 들어 req.query / req.body , res.send / res. redirect 등등..

 

그러면 추가로 넣어준 next 인자의 역할은 무엇일까?

 

미들웨어 코드실행이 끝났으니 다음으로 이동시켜주는 역할을 한다.

 

이 next() 가 없으면 클라이언트는 무한대기 상태에 빠진다..

 

미들웨어는 아래와 같이 array를 통해 여러 개를 넣을 수 있다.

app.get('/login', [func1, func2, func3] ,(req, res) => {
    res.send('success login')
})

 

=> 미들웨어는 func1, func2, func3 순으로 실행된다.

 

개발을 하다보면 수 많은 API에 미들웨어를 전부 적용하고 싶은 순간이 생길 것 이다. 이 땐 app.use()를 사용해주면 된다.

 

const login = (req, res, next) => {
    if(!req.user){
        res.send('cannot login')
    }
    next()
}

app.use(login)

app.get('/', (req, res) => {
    res.send('success login')
})

app.get('/login', (req, res) => {
    res.send('success login')
})

 

=> app.use(login) 밑에 있는 모든 API에는 모두 login 미들웨어가 적용된다.

 

참고로 이 app.use()를 사용하면 제한사항을 넣을 수 있다. 

 

app.use('/URL', login)

 

=> app.use()에 위와같이 URL을 넣어주면 이 URL과 일치하는 API에 get, post, put, delete 요청이 들어올 때만 login 미들웨어를 실행시켜 줄 수 있다.

 

이러면 원하는 route 에만 적용할 수 있다. (참고로 /URL의 하위 URL에도 모두 적용시키게 된다.)

 

명심해야 할 점은 항상 app.use() 밑에있는 API들에만 적용 할 수 있다. = 항상 파일 위쪽에 app.use()를 넣어줄 것.