[Browser] CORS, 너 싸움 잘하냐?
CORS Error
개인 프로젝트를 진행하다, 공공데이터 포탈에 데이터 요청을 보내다가 CORS 에러를 만나게 되었다.
구글링을 시작하자마자 뜨는 문구가 프론트엔드 개발을 하다보면 한번씩은 꼭 만난다는 에러라고 한다,,
그래도 한번에 확실하게 잡고 가고 싶어서 공부해보려 한다.
CORS가 뭔데?
Cross Origin Resource Sharing : 교차출처 리소스 공유 브라우저에서 출처가 다른 HTTP요청을 제한하는 정책이다.
Origin이란?
흔히들 사용하는 URL 주소는 위 그림과 같이 분류된다. 여기서 Origin이란 protocol + host + port를 의미한다. 즉, 서버를 찾아가기 위한 가장 기본의 주소인 것이다. 하지만, 여기서 우리는 주소를 볼 때 대부분 포트 번호를 쉽게 찾아볼 수 없다. 그 이유는 http는 80번, https 는 443번 포트가 Default 값으로 지정되어 있기 때문이다.
Cross Origin이란?
위에서 말한 Origin이 다른 것을 의미한다. 예를 들어, https://Majesty-jun.github.io 라는 URL이 있다고 가정해보자.
URL | result | reason |
---|---|---|
https://Majesty-jun.github.io/about | 같은 출처 | Protocol, Host, Port 동일 |
https://Majesty-jun.github.io/about?page=1 | 같은 출처 | Protocol, Host, Port 동일 |
http://Majesty-jun.github.io | 다른 출처 | Protocol 불일치 |
https://Majesty-jun.test.io | 다른 출처 | Host 불일치 |
https://Majesty-jun.github.io:1234 | 다른 출처 | Port 불일치 |
하지막 포트 번호가 다른 경우는 https의 Default 포트 번호가 443이기에 다른 출처이긴 하나, 애초에 예시 주소에 포트번호가 명시되어 있지 않기 때문에 실질적으로 판단하기 애매하다고 한다.
CORS 에러의 동작 원리
기본적으로 웹에서 다른 출처로 리소스를 요청할 때에는 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이 과정에서 브라우저는 origin이라는 필드에 요청을 보내는 출처를 담아서 보내게 된다.
이후 서버가 이 요청에 대한 응답을 할 때, Access-Control-Allow-Origin이라는 필드에 리소스에 접근하는 것이 혀용된 출처를 보내주고, 브라우저에서 요청한 Origin과 응답받은 Access-Control-Allow-Origin 필드를 비교 후 유효성을 판별한다고 한다.
CORS 에러 해결 방법
1. 이미 만들어진 프록시 서버 사용하기.
프록시 서버는 클라이언트가 프록시 서버를 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해준다. 브라우저와 서버 간의 통신을 도와주는 중계서버라고 생각하면 편하다.
https://cors-anywhere/herokuapp.com
이 서버를 사용하면 중간에 요청을 가로채서 HTTP 응답 헤더에 Access-Control-Allow-Origin 필드를 * 로 설정해준다.
2. http-proxy-middleware 사용하기.
배포 전, 개발환경에서 사용하기 좋은 라이브러리이다. 로컬환경에서만 한정적으로 가능하다. setupProxy.js 파일을 src폴더 내에 생성한 후 아래와 같은 코드를 작성해준다.
npm i http-proxy-middleware
// setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function(app) {
app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:3000",
changeOrigin: true,
})
)
}
3. rewrites 메서드 사용 (NextJS)
나는 NextJS를 사용해서 이 방법을 선택했다. endpoint를 마스킹 하는 느낌이라고 생각하면 된다. 실제로는 destination으로 api 요청을 보내는데, source로 보내는 것 처럼 하고 싶을 때 사용하는 느낌이다.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{
source: '/요청하는 주소',
destination: 'http://API 요청 주소/:path*',
},
];
},
};
module.exports = nextConfig;
4. Access-Control-Allow-Origin 헤더 세팅
CORS 해결의 정석적인 방법이라고 한다. 직접 서버에서 HTTP 헤더 설정을 통해 출처를 허용하게 설정하는 것이다. 하지만 이것은 백엔드 개발자와의 대화, 소통이 필요한 부분이기에 애초에 백엔드 개발자가 존재해야 하고, 나처럼 Open API를 사용하여 개발하는 사람에게는 의미가 없다..ㅠ
정리
CORS란 출처가 다른 HTTP 요청을 제한하는 정책이고, 요청을 보내는 Origin과 응답 받은 Access-Control-Allow-Origin을 비교함으로써 동작한다. 서버에서 유효한 값을 포함해서 보내주거나, 이미 만들어진 프록시 서버를 사용하는 방법 등이 있다. 아무래도 직접 CORS에러를 경험해보고 이렇게 정리해두는 게 좋을 것 같다.
부록
부록1 : 프론트에서 CORS를 해결하는 이유?
서버에서 CORS에러에 대해 문제를 해결하면 되는데 왜 프론트에서 해야하나 싶을것이다. 하지만, 만약 서비스가 배포된 상태라면, 수정이 어렵기 때문에 프론트 단에서 화이팅 해준다는 답변을 찾아볼 수 있었다..
부록2: SOP
Same-Origin Policy의 약자로, 같은 출처에서만 리소스를 공유할 수 있다는 규칙을 가진 정책.
댓글남기기