기본적으로 브라우저에서 API를 요청할 때, 현재 주소와 API의 주소의 도메인이 일치해야만 데이터에 접근이 가능한데, 만약 서로 다른 도메인에서 API를 요청해 데이터를 사용할 수 있게 해주려면 추가적인 헤더가 필요하고, 이를 CORS정책이라고 한다.
CORS
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제.
출처
웹 콘텐츠의 출처(origin)는 접근할 때 사용하는 URL의 스킴(프로토콜), 호스트(도메인), 포트로 정의됩니다. 두 객체의 스킴, 호스트, 포트가 모두 일치하는 경우 같은 출처를 가졌다고 말한다..
일부 작업은 동일 출처 콘텐츠로 제한되나, CORS를 통해 제한을 해제할 수 있다.
상용 앱을 운영할 때, 클라이언트 뒤의 서버와 연결된 DB에는 라이브 데이터가 쌓인다.
라이브 데이터(live data)
실제 서비스되고 있는 앱의 데이터베이스(Data Base, DB)에 적재되고 있는 데이터. (유저 및 상품, 결제 등 다양한 정보)
모든 출처에서 이러한 라이브 데이터에 접근을 허락하면 보안성이 낮아지고, 해킹의 위험에 노출된다. 따라서 모든 도메인에 대해 접근을 허락하는 것이 아니라 특정 도메인에만 접근을 허락하는 것이다.
React 라이브러리, Webpack Dev Server에서 제공하는 proxy 기능을 사용하면 CORS 정책을 우회할 수 있다.
React앱에서 브라우저를 통해 api를 요청할 때, proxy를 통해 백엔드 서버로 요청을 우회해서 보낸다. 백엔드 서버는 응답을 React앱으로 보내고, react앱은 받은 응답을 백엔드 서버 대신 브라우저에게 전달하는 것이다.
webpack dev server에서 기본적으로 제공하는 proxy기능을 이용할 수 있다. 이를 이용하면 api를 요청할 때 서버에 직접 하는 것이 아니라, 현 개발서버의 주소로 우회 요청ㅇ르 하게 된다.
원래 웹팩 설정을 통해 하지만, CRA를 통해 만든 리액트 프로젝트엣너느 package.json에서 "proxy"값을 설정해 쉽게 적용할 수 있도록 구성되어 있다.
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy" : "우회할 API 주소"
}
보통 구분하기 쉽게 맨 밑에 작성한다.
이후 기존의 fetch, axios를 통한 요청부분에서 도메인 부분을 제거한다.
export async function getAllfetch() {
const response = await fetch('우회할 api주소/params');
.then(() => {
...
})
}
'
' // 이렇게
'
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}
위의 방법은 전역적인 설정이기 때문에, 종종 방법이 적용이 안되는 경우가 발생한다. 그래서 수동으로 proxy를 적용해줘야 하는 경우, http-proxy-middleware 라이브러리를 사용해야 한다.
npm install http-proxy-middleware --save
이후 react app의 src파일 안에서 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, //대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분
})
);
};
그리고 마찬가지로, 기존의 요청에서 도메인을 제거한다.
export async function getAllfetch() {
const response = await fetch('우회할 api주소/params');
.then(() => {
...
})
}
'
' // 이렇게
'
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}