React Proxy

iberis2·2023년 4월 4일
1

React 리액트

목록 보기
9/20

Proxy 서버

클라이언트 ⇄ 프록시 서버 ⇄ API 서버

프록시란 대리인 이라는 뜻이다.

클라이언트가 API 서버에 보내는 요청과
API 서버에서 클라이언트에 보내는 응답을 중간에서 대신 전달해줌으로써,

직접적인 통신이 아닌 간접적인 통신을 가능하게 해준다.

프록시 서버의 중요 역할

1. 캐싱 역할
프록시 서버가 API 서버에서 받은 응답을 캐시해둔다.

  • 이후 같은 요청이 들어오면 캐시해 둔 응답에서 바로 전달해준다.
    (서버에 재요청하지 않음으로써) 불필요한 네트워크 리소스를 줄인다.

2. 보안의 역할
프록시를 통하지 않은 직접적인 통신을 하는 경우 클라이언트와 서버의 정보가 서로에게 노출된다.

  • 클라이언트의 접속 정보, 위치 정보 등 개인정보가 서버측에 노출된다.
  • API 서버 정보도 노출되어, 서버에 직접적인 공격을 가하기 쉽다.

프록시 서버를 통해 통신하는 경우, 클라이언트의 IP 주소를 감춰준다.

  • 클라이언트의 접속 정보, 위치 정보 등 개인정보를 보호할 수 있다.
  • 서버의 위치, 주소도 감춰주기 때문에 익명의 사용자도 서버에 직접적으로 접근하기 어려워진다.

3.IP 주소 우회

4.인터넷 사용을 제어
이상한 접근을 감지하는 경우 그 접근을 제어할 수 있다.

  • 해외에서 로그인 차단
  • 이상할 정도로 많은 트래픽 감지 등
  • 자녀의 컴퓨터로 이상한 사이트에 접속하지 못하도록 차단

보다 자세한 프록시의 역할과 프록시 사용의 위험성은 링크 참조
🔗 프록시 서버: 프록시 서버란 무엇인지? 당신도 필요할까요?

React Proxy

리액트(프론트 서버)에서 백앤드 서버로 요청할 때 프록시가 중간에 대신 요청을 전달하고 응답을 받아와준다.

개발 단계에서 로컬 환경(localhost)에서 실행될 때, API 서버와 통신할 일이 많은데, 이때 개발 서버에 Proxy를 설정하면 CORS 에러를 해결하고, 다른 도메인과의 통신이 원활해진다.

CORS (교차 출처 리소스 공유)
CORS(Cross-Origin Resource Sharing)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다.

  • 출처 : URL의 스킴(프로토콜), 호스트(도메인), 포트
    • 두 객체의 스킴, 호스트, 포트가 모두 일치하는 경우 같은 출처를 가졌다고 말합니다.
    • 일부 작업은 동일 출처 콘텐츠로 제한되나, CORS를 통해 제한을 해제할 수 있습니다.

React Proxy 를 사용하는 이유

실제 서버에서는 리액트와와 백엔드 서버가 같은 주소(포트)의 서버에서 실행될 것이므로 동일 출처가 된다.

하지만 개발환경에서 dev 서버를 사용하면, 리액트(프로트)와 백앤드 서버는 서로 다른 출처(포트)로 열게 된다.
이 때 리액트에서 다른 출처로 API요청(GET, POST 등)을 하면, CORS 에러가 발생하게 된다. 이 경우 보통 프론트엔드 개발자가 백엔드 개발자에게 프론트엔드 개발 서버 도메인을 허용해달라고 요청하고 백엔드 개발자는 응답 헤더의 Access-Control-Allow-Origin에 허용하는 origin(주소)를 담아서 응답하는 과정을 거친다.

하지만 위와 같은 백앤드의 허용 과정 없이도 React Proxy 를 사용하면 CORS 정책을 우회할 수 있다.

🔗 이미지 출처 : 생활코딩-Create React App - Proxy

예를 들어, React 앱에서 브라우저를 통해 API를 요청하는 상황에서 proxy를 사용하면 다음과 같은 과정을 거친다.

  • proxy를 사용하면 백엔드 서버로 요청을 우회하여 보낸다.
  • 백엔드 서버는 응답을 React 앱으로 보낸다.
  • React 앱은 받은 응답을 백엔드 서버 대신 브라우저에게 전달한다.
  • 이렇게 되면 출처가 같아져서 브라우저는 이를 허용한다.

즉, proxy로 우회하여 브라우저를 같은 출처인 것처럼 속이고, CORS 에러가 발생하지 않도록 하는 것이다.

사용법

webpack dev server proxy

webpack dev server의 proxy를 사용하게 되면, 브라우저 API를 요청할 때 백엔드 서버에 직접적으로 요청을 하지 않고, 현재 개발서버의 주소로 우회 요청을 한다. 그러면 웹팩 개발 서버에서 해당 요청을 받아 그대로 백엔드 서버로 전달하고, 백엔드 서버에서 응답한 내용을 다시 브라우저쪽으로 반환합니다.

CRA 를 통해 만든 리액트 프로젝트에서는 package.json 에서 proxy 값을 설정하면 된다.
(웹팩 개발서버의 proxy 설정은 원래 웹팩 설정을 통해서 적용해야 함)

// package.json 파일
{ ... 
"development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
"proxy" : "우회할 API 주소" //예를 들어 "http://localhost:3000"
}
// .jsx 파일
export async function getAllfetch() {
		
		// fetch()안에 들어가는 도메인 주소를 삭제하고, params만 남겨놓으면 된다.	
		// 예를 들어 "http://localhost:3000/params" → "/params"
    const response = await fetch('/params'); 
    .then(() => {
			...
		})
}

React Proxy : http-proxy-middleware 미들웨어

webpack dev server 에서 제공하는 proxy는 전역적인 설정이므로,
2개 이상의 도메인을 사용하기 어렵다.
(특히 CRA로 만든 경우 package.json에 proxy 설정을 1개만 할 수 있다.)

여러 도메인을 사용하는 경우,
http-proxy-middleware 라이브러리를 사용할 수 있다.

# 터미널에서 라이브러리 설치
npm install http-proxy-middleware

src 폴더 안에서 setupProxy.js 파일을 생성하고, 안에서 설치한 라이브러리 파일을 불러온 다음, 아래와 같이 작성 한다.

  • 파일 이름은 setupProxy.js 외 다른 이름으로 할 수 없다.
// setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api', //proxy가 필요한 path prameter를 입력합니다.
    createProxyMiddleware({
      target: 'http://localhost:5000', //타겟이 되는 api url를 입력합니다.
      changeOrigin: true, //대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분입니다.
    })
  );

// 여러 도메인 사용하는 경우
  app.use(
    '/api2', 
    createProxyMiddleware({
      target: 'http://localhost:4000', 
      changeOrigin: true,
    })
  );
};

여러 주소를 하나의 app.use()에 쓰고 싶은 경우

// setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
      ['/api', '/api2', '/api3'],
      createProxyMiddleware({
      target: "http://localhost:3080", // 가장 베이스가 되는 것, 배열 맨 앞 api의 주소
      changeOrigin: true,
       router:{
          '/api2': "http://localhost:3070"
          '/api3': "http://localhost:4000"
       }

      })
  )
}
// .jsx 파일, 컴포넌트는 동일하게 params 만 남겨놓으면 된다.
export async function getAllfetch() {
		
    const response = await fetch('/params'); 
    .then(() => {
			...
		})
}
profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글