서버는 민감한 유저 정보를 지니기 때문에 안전한 출처의 접근에만 리소스를 응답해야 한다.
때문에 모든 출처를 허용하는 * 와일드 카드의 사용은 지양해야한다.
개발 단계에서 정석적인 교차출처 접근 방법은 백엔드 서버에서 개발서버 도메인을 허용하는 것이지만 개발 서버에서 proxy를 통해 cors를 우회하는 방법도 존재한다.
서버와 클라이언트 사이에 중계기로서 대리로 통신을 수행하며, 중계 기능을 하는 서버를 Proxy server 라고 부른다.
React 라이브러리, 혹은 Webpack Dev Server에서 제공하는 proxy 기능을 사용해 개발하는 동안 CORS 정책을 우회할 수 있다.
일반적인 요청/응답 흐름은 다음과 같다.
애플리케이션에서 브라우저로 요청 전송
브라우저에서 서버로 리소스 요청
서버는 접근 권한을 확인 후 응답으로 리소스 전달
브라우저가 요청과 리소스의 출처가 같은지 확인 후 애플리케이션으로 전달
여기에 proxy를 사용하면 다음과 같은 흐름을 보인다.
애플리케이션에서 브라우저를 통해 API 요청을 할 때 proxy를 통해 서버로 요청을 우회
서버로부터 받은 응답을 proxy를 통해 애플리케이션이 받고 브라우저에게 전달
최종적으로 브라우저는 요청과 리소스가 같은 출처라고 판단하게 된다.
개발 단계에서 크게 2가지 방법으로 proxy를 설정할 수 있다.
webpack dev server는 proxy기능을 제공한다.
이 방법을 사용하면 브라우저 API를 요청할 때 백엔드 서버에 직접적으로 요청을 하지 않고, 현재 개발서버의 주소로 우회 요청을 보낸다.
webpack을 직접 구성한 경우 webpack 설정을 통해서 적용한다.
// webpack.config.js
module.exports = {
devServer: {
proxy: {
'/api': 'http://localhost:3000'
// 주소가 domain name인 경우 아래와 같이 설정한다.
'/api': {
target: 'domain.com',
changeOrigin: true
}
}
}
};
CRA로 시작한 경우 package.json에서 proxy 값을 설정한다.
//package.json
{
... ,
"proxy" : "http://localhost:3000"
}
설정을 완료하면 애플이케이션 내에서 다음과 같이 fetch, axios 요청을 한다.
// app.js
// 기존 리소스 요청 방식
const response = fetch('http://localhost:3000/params');
.then(() => {
//...
})
// proxy 사용시 리소스 요청 방식
const response = fetch('/params');
.then(() => {
//...
})
webpack dev server 에서 제공하는 proxy는 전역적인 설정이기 때문에, 종종 해당 방법이 충분히 적용되지 않는 경우가 생긴다. 때문에 수동으로 proxy를 적용해줘야 하는 경우 http-proxy-middleware 라이브러리를 사용할 수 있다.
npm install http-proxy-middleware -- save
src 파일 내에 setupProxy.js를 생성하고, 다음과 같이 작성한다.
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api1', // proxy가 필요한 path prameter
createProxyMiddleware({
target: 'http://localhost:3000',
changeOrigin: true // 대상 서버 구성에 따라 호스트 헤더가 변경
})
);
// 2개의 서버에서 리소스를 받아오는 경우 다음과 같이 app.use를 하나더 작성할 수 있다.
app.use(
'/api2',
createProxyMiddleware({
target: 'http://localhost:3000',
changeOrigin: true
})
);
}
설정을 완료하면 애플이케이션 내에서 다음과 같이 fetch, axios 요청을 한다.
// app.js
// 기존 리소스 요청 방식
const response = fetch('http://localhost:3000/params');
.then(() => {
//...
})
// proxy 사용시 리소스 요청 방식
const response = fetch('/params');
.then(() => {
//...
})
Reference
코드스테이츠