본문 바로가기

javascript/react

[React] 개발 환경 프록시 설정

 개발 환경에서 프록시를 설정하지 않는 경우 CORS 에러가 발생할 수 있다. 실제 배포 환경에서는 nginx 등 웹 서버에 빌드 된 파일들을 올리기 때문에 이런 문제를 고민할 필요가 없으나, 개발 환경은 그렇지 않다. 다행히도 CRA 또는 Vite을 이용하는 경우 개발 환경에서 프록시를 설정할 수 있도록 기능을 지원하고 있다.

CRA(Create-React-App)를 사용하는 경우

https://create-react-app.dev/docs/proxying-api-requests-in-development

두가지 방법이 존재하나, 후자가 좀 더 정밀한 사용이 가능하다.

  1. package.json 파일 내에 "proxy" 정의
  2. http-proxy-middleware 을 설치한 후, src 폴더 내에 setupProxy.js 파일 정의

package.json 파일 내에는 다음과 같이 정의할 수 있다.

... 다른 명령들
... dependency,name 등과 동일한 레벨 상에 정의
"proxy":"http://localhost:5000"

 다만 이 방식은 그렇게까지 유연한 편이 아니다. 따로 rewrite 규칙을 설정할 수 없으므로 사용자가 설정한 proxy를 host로 삼은 후 path를 단순히 이어 붙여서 서버에 요청하게 된다.

useEffect(() => {
    (async () => {
        const result = await axios.get('/api/create', {timeout: 3000});
        console.log(result.status);
        if(result.status === 200)
        {
            console.log(result.data);
        }
    })();

 위 코드는 프론트엔드에서 특정 페이지를 방문할 때 서버에서 전달된 결과를 반환하도록 작성한 것이다.

server.use((req,res,next) => {
    console.log(req.originalUrl);
    next();
})

server.use('/create', codeRouter);
server.use('*', (req,res,next) =>{
    res.send("error!");
})

 서버의 경우 들어오는 모든 경로에 대해 요청된 path 정보를 출력하도록 구성해 두었으며, /create 경로가 아닌 경우 에러 메시지를 출력한다. 이 조건에서 발생하는 결과는 다음과 같았다.

서버측에서 콘솔에 출력한 문자들

 프론트엔드에서 서버에 요청한 /api/create 경로에 대한 GET 요청은 rewrite 없이 그대로 서버에 전달되었다. 따라서 서버 상에 존재하는 /create 경로와 매칭되지 않으므로 '*' 와 매칭되어 error!을 반환하게 된다.

브라우저 콘솔에 출력된 글자들

 여기서 status code가 200인 이유는 서버 상에서 error!을 출력할 때 딱히 status을 설정하지 않았기 때문이므로 혼동하지 말자. 중요한 점은 /api/create 경로가 그대로 서버 상에 전달된다는 것이다. 이 경우 프론트엔드에 연결되는 백엔드가 1개인 경우에는 크게 문제가 없지만, 만약 연결되는 서버가 여러개라 /server1 , /server2 와 같이 구분하여 나타내고 싶은 상황에서는 처리할 수 없는 문제점이 있다. 이러한 복잡한 상황에서는 http-proxy-middleware을 사용하여 프록시를 설정한다.


https://www.npmjs.com/package/http-proxy-middleware

 

http-proxy-middleware

The one-liner node.js proxy middleware for connect, express and browser-sync. Latest version: 2.0.6, last published: 8 months ago. Start using http-proxy-middleware in your project by running `npm i http-proxy-middleware`. There are 3254 other projects in

www.npmjs.com

 http-proxy-middleware는 이름에서 알 수 있듯이 express 서버의 미들웨어 역할을 수행한다. CRA을 이용하는 경우 react-script 라이브러리에 의해 express 서버를 이용, 해당 라이브러리를 사용할 수 있는 것으로 보인다.

 이 라이브러리의 경우 기본적으로 설치되어 있지 않으므로 npm 또는 yarn을 이용하여 개발 환경으로 설치하자. React로 구성한 프론트엔드는 어차피 배포 시점에는 nginx와 같은 웹 서버의 html 폴더로 들어가서 해당 웹서버의 프록시 지정 방식을 따르기 때문에, 배포 환경에 코드 상으로 포함될 필요가 전혀 없다.

//npm을 사용하는 경우
npm install --save-dev http-proxy-middleware

//yarn을 사용하는 경우
yarn install --dev http-proxy-middleware

 setupProxy.js 파일의 코드는 CRA 공식문서를 참조하자. 다음과 같이 구성해도 된다.

const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
    app.use('/api',
        createProxyMiddleware({
            target: 'http://localhost:5000',
            changeOrigin: true,
            pathRewrite: { '^/api': '/' }
        })
    );
}
// /src/setupProxy.js

여기서 중요한 점이 몇 개 존재한다. 

  1. 파일은 /src 폴더 안에 바로 위치해야 한다.
  2. 파일의 이름은 반드시 setupProxy.js로 지정해야 한다. 타입스크립트라고 ts로 지정하면 동작하지 않는다!
  3. arrow function 형식으로 나타내서 동작하지 않는다면 function 구문으로 바꿔보자.

사실 맨 마지막 때문에 작성했다. 이게 실제로 arrow function을 인식하지 못하는 것인지는 모르겠으나, 나의 경우 arrow function 형태를 일반적인 function으로 변경했을 때부터 프록시 설정이 제대로 인식되었다. 

 개인적으로 이 방식의 장점은 rewrite가 동작한다는 점이라고 생각한다. 다음 코드를 보자.

// 프론트엔드 중
const result = await axios.post('/api/create', urlparams, {
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    }
});

 프론트엔드의 어떤 부분에서는 http POST 메서드를 이용하여 /api/create 경로로 요청하고 있다. 이때 백엔드에서는 현재 프론트엔드에서 받은 데이터를 파싱하여 그대로 반환하는 동작을 수행한다. 결과는 다음과 같다.

프론트엔드의 입력 부분
서버에서의 인식
프론트엔드에서 받은 데이터

 프론트엔드에서는 /api/create 경로로 POST 요청을 보냈지만, setupProxy.js 파일에 정의된 rewrite 규칙에 의해 /api path가 제거된 형태로 서버에서 인식할 수 있었다.


Vite을 사용하는 경우

 CRA의 경우 번들러로 webpack을 사용하나, 관련된 의존성은 react-scripts에 숨겨져 있다. 이때 위에서 설명한 방법들은 기본적으로 react-scripts에서 지원하는 기능이므로 vite를 번들러로 사용하는 프로젝트에서는 당연히 사용할 수 없다.

 대신 vite는 react 전용 플러그인을 제공함으로써 프록시 설정을 수행할 수 있도록 도와준다. 

https://vitejs-kr.github.io/guide/#trying-vite-online: vite에서 지원하는 템플릿들

npm create vite my-app --template react-ts
yarn create vite my-app --template react-ts

 vite을 이용하여 프로젝트를 만드는 경우 프로젝트 폴더의 가장 상위(src 폴더 바깥)에 vite.config.ts 파일이 생성된다. 해당 파일의 기본 값은 다음과 같다.

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()]
})

여기에 server -> proxy 형태로 코드를 작성할 수 있다.

import {defineConfig} from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [react()],
    server: {
        proxy: {
            '/api' : {
                target: 'http://localhost:5000',
                changeOrigin: true
            }
        }
    }
})

 vite 자체적으로 미리 기능을 지원해둬서 CRA보다 더 편리하다고 느꼈다. 다만 CRA + webpack을 전제로 만들어진 유용한 컴포넌트들이 npm 상에 가끔 존재해서 vite 기반 리액트가 성능이 더 잘 나온다고 해도 쉽게 갈아타기는 힘든 것 같다.

 

'javascript > react' 카테고리의 다른 글

[React-Quill] 에디터 영역 스크롤 바 만들기  (0) 2023.09.10
[React] 타입스크립트와 children 사용  (0) 2022.10.01
[React] react-router  (0) 2022.01.06
[React] custom hook  (0) 2021.12.29
[React] react-redux  (0) 2021.12.24