https://a.domain.com
에서 https://server.domain.com
으로 요청을 하고 있습니다.
이때, CORS가 발생해서 이슈를 해결한 과정을 작성하려고 합니다.
CORS는 브라우저가 리소스 로드를 허용해야 하는 자체 출처 이외의 모든 출처 (도메인, 스키마 또는 포트)를 서버가 표시할 수 있도록 합니다. 이 때문에 브라우저에서 서로 다른 도메인으로 요청을 하는 경우 에러가 발생합니다. 이러한, CORS를 해결하기 위해서는 몇가지 설정이 필요합니다.
CORS를 마주한 뒤 개발자 모드에서 Network 탭을 확인하면 아래와 같이 서버 요청이 실패한 것을 볼 수 있습니다.
요청 흐름은 다음과 같습니다.
Browser Nginx Spring
Request => preflight => 405
fetch는 브라우저에서 서버로의 요청이라면 두 번째 preflight는 서로 다른 도메인으로 브라우저에서 서버가 해당 요청에 응하는지 확인하기 위한 말 그대로 'preflight'이고 브라우저는 preflight가 성공한 다음 원문 요청을 보내게 됩니다.
웹 서버의 Nginx 설정을 확인하면 아래와 같습니다.
// GET || POST 요청 외에는 405를 응답한다.
if ( $request_method !~ ^(GET|POST)$ ) {
return 405;
}
// Root 경로로 접근하면 index.html을 가져온다.
location / {
root /data;
index index.html;
try_files $uri https://$uri/ /index.html;
}
여기서 확인할 점은 preflight의 Method입니다. preflight는 OPTIONS Method로 Nginx의 request_method에 OPTIONS를 추가해야 합니다.
if ( $request_method !~ ^(GET|POST|OPTIONS)$ ) {
return 405;
}
위와 같이 설정하면 다른 도메인에서 요청 시에 아래의 과정을 거칠 수 있게 됩니다.
Browser Nginx Spring
Request => preflight =>
<= Response <= Response
preflight가 성공적으로 송수신되었으니 원문을 요청할 시간입니다.
--- Preflight
Browser Nginx Spring
Request => preflight =>
<= Response <= Response
--- 원문
=> request => 400
Spring은 내부적으로 CrossOrigin을 확인하고 도메인이 다를 경우 막는 코드가 존재할 수 있습니다.
Spring의 originPattern에 https://*.domain.com
과 같이 다른 도메인의 요청을 허용할 수 있도록 추가해야합니다.
--- Preflight
Browser Nginx Spring
Request => preflight =>
<= Response <= Response
--- 원문
=> request => Response
<= Response <= Response
CORS는 구글링을 통해서 해결책을 찾을 수 없어서 고생했던 기억이 있습니다.
사실 CORS는 웹 개발자 혼자 해결할 수 있는 문제가 아니다 보니 구글링을 해도 올바른 답을 찾을 수가 없었습니다. 그래서 회사의 인프라 및 서버 개발자 분과 Nginx 및 Spring 설정을 변경하면서 해결책을 찾아갔습니다.
막상 고생해서 해결책을 찾고나니 구글링하면서 엄청나게 마주했던 위의 이미지의 내용이 이해되고 적어도 현재 회사에서는 CORS로 고생하는 일은 없어졌던 것 같습니다.