이전부터 개발을 하면서 미들웨어를 많이 접할 기회가 많았다. 그치만 우선 개발 목표를 달성하는데에 바빠서 미들웨어는 제쳐놓고 개발을 했었다. 그래서 항상 도대체 미들웨어가 뭔데?! 라는 궁금증이 들었다. 이번 기회에 미들웨어에 대해서 알아보고자 한다!
미들웨어는 서로 다른 어플리케이션이 서로 통신하는데 사용되는 소프트웨어이다. 미들웨어는 더욱 빠르게 혁신할 수 있도록 어플리케이션을 지능적으고 효율으로 연결하는 기능을 제공한다. 미들웨어는 단일 시스템에 원할하게 통합할 수 있도록 다양한 기술, 도구, 데이터베이스 간에 다리 역할을 한다. 그 다음 이 단일 시스템은 사용자에게 통합된 서비스를 제공한다.
미들웨어는 구성 요소 간의 기본 통신 프로세스를 담당한다.
메시징 프레임워크는 프론트엔드 어플리케이션과 백엔드 어플리케이션 간의 데이터 교환이 원할하게 이루어지도록 한다.
메시징 프레임워크는 서로 다른 운영 체제 및 언어의 어플리케이션에 대해 공통 통신 어플리케이션을 제공한다. 어플리케이션은 메시징 프레임워크에서 제공하는 표준 형식의 데이터를 쓰고 읽는다.
미들웨어는 업무를 줄여주는 상호 운용성을 제공하는 것 외에도 개발자를 돕는 서비스도 포함한다.
클라이언트 또는 프론트엔드 어플리케이션 요청의 정보를 기반으로 미들웨어는 백엔드 어플리케이션 또는 서비스의 응답을 사용자 정의할 수 있다.
미들웨어는 일반적으로 TSL(Transport Layer Security) 또는 다른 네트워크 보안 프로토콜을 사용하여 프론트엔드 어플리케이션에서 백엔드 데이터 소스로의 연결을 보호한다. 또한 프론트엔드 어플리케이션이 신임 정보(사용자의 이름이나 비밀번호)나 디지털 인증서를 요구하는 관행에 도전하는 인증 기능을 제공할 수 있다.
어플리케이션 트래픽이 급증하면 엔터프라이즈 미들웨어는 클라이언트 요청을 온프레미스 또는 클라우드의 여러 서버에 분산하도록 확장할 수 있다. 또한 동시 처리 기능은 여러 클라이언트가 동일한 백엔드 데이터 소스에 동시에 엑세스하려고 할 때 생기는 문제를 방지할 수 있다.
결국 미들웨어는 중간 매개 역할을 하는 소프트웨어를 말하는데, 매개체 간에서 연결해주는 레이어로써 관리하려는 내용을 세부적으로 나눠 발생할 수 있는 에러를 최소화하려는(?) 목적으로 사용하는 것으로 이해했다.
하나의 서버가 모두를 관리하기 보다는 세부적으로 나누어 관리함으로써 개발/관리/유지하는데 더 편하게 할 수 있어서 미들웨어를 사용하는 것으로 이해했다.
자세한 것은 이 velog 포스팅을 참고!
리덕스 미들웨어를 사용하면 액션이 디스패치된 다음, 리듀서에서 해당 액션을 받아와서 업데이트하기 전에 추가적인 작업을 할 수 있다.
주로 리덕스에서 미들웨어를 사용하는 주된 이유는 비동기 작업을 처리할 때이다. 리액트 앱에서 백엔드 API를 연동해야한다면 리덕스의 미들웨어를 사용하여 처리하기도 한다.
리덕스 미들웨어를 만들어서 사용할 수도 있겠지만 주로 리덕스 미들웨어 라이브러리를 사용한다.
redux-thunk는 이전에 Udemy를 통해 리액트/리덕스를 배웠을 때 잠깐 스쳐 지나갔던 내용이었다.
우선 redux-thunk는 리덕스에서 비동기 작업을 처리할 때 가장 많이 사용하는 미들웨어이다. 이 미들웨어를 사용하면 액션 객체가 아닌 함수를 디스패치할 수 있다.
then, catch를 사용하는 방법const getComments = () => (dispatch, getState) => {
// 이 안에서 액션을 dispatch할 수도 있고 getState를 이용해 현재 상태도 조회할 수 있다.
const id = getState().post.activeId;
dispatch({type: 'GET_COMMENTS'});
// 댓글을 조회하는 프로미스를 반환하는 getComments가 있다로 가정
api
.getComments(id)
.then(comments=> dispatch({type:'GET_COMMENTS_SUCCESS', id, comments})) // 성공 시
.catch(e=> dispatch({type:'GET_COMMENTS_ERROR', error: e})); // 실패 시
}
async/await 사용하는 방법const getComments = () => async (dispatch, getState) => {
const id = getState().post.activeId;
dispatch({type:'GET_COMMENTS'});
try{
const comments = await api.getComments(id);
dispatch({type: 'GET_COMMENTS_SUCCESS', id, comments}));
} catch(e){
dispatch({type: 'GET_COMMENTS_ERROR', error:e}));
}
}
Next.js의 미들웨어는 페이지를 렌더링하기 전에 서버측에서 실행되는 함수이다. 미들웨어에서는 Request 객체와 Response 객체에 접근할 수 있으며 이를 활용해 요청 정보를 받아와 부가적인 처리를 하고 응답 객체에 무언가를 추가하거나 응답을 변경할 수 있다.
미들웨어 사용하는 경우
middleware.ts(혹은 js)를 생성한다.import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}
// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}
미들웨어는 기본적으로 모든 라우트에 대해 순차적으로 동작한다.
next.config.js의headersnext.config.js의redirects- 미들웨어
next.config.js의beforeFiles- 파일 시스템의 모든 파일(
public/,_next/static/,pages/,app/, etc.)next.config.js의afterFiles- 다이나믹 라우트들(
/blog/[slug])next.config.js의fallback
config의 matcher를 설정하여 원하는 경로에 미들웨어를 적용