웹 개발

javascript ajax 크로스 도메인 요청하기(CORS)

노루아부지 2020. 9. 30. 00:18

javascript에서 ajax 요청을 보내면 브라우저 콘솔에 아래와 같이 에러가 나면서 요청이 실패합니다.

1) 크롬

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ‘[요청한 도메인]' is therefore not allowed access.

2) 파이어폭스

교차 원본 요청 차단: 동일 출처 정책으로 인해 [요청한 도메인]에 있는 원격 자원을 읽을 수 없습니다. 자원을 같은 도메인으로 이동시키거나 CORS를 활성화하여 해결할 수 있습니다.

이 오류가 발생하는 이유는 아래와 같습니다.

 

 

 

교차 출처 리소스 공유

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

ex) http://domain-a.com에서 http://domain-b.com/data.json을 요청하는 경우

보안 상의 이유로, 브라우저는 script에서 시작한 HTTP 요청을 제한합니다. 예를 들어 XMLHttpRequest는 동일 출처 정책을 따릅니다. 즉, 자신의 출처와 동일한 리소스만 호출할 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 합니다.

HTTP 요청 방식에는 두 가지 방법이 있습니다.

 

 

1. Simple Request(공식 용어는 아님)

아래 조건을 모두 충족하는 요청의 경우 CORS preflight를 트리거 하지 않습니다.

1) 다음 중 하나의 method

→ GET

→ HEAD

→ POST

2) User agent가 자동으로 설정한 header

→ Accept

→ Accept-Language

→ Content-Language

→ Content-Type(아래 추가 요구 사항을 만족해야 함)

→ DPR

→ Downlink

→ Save-Data

→ Viewport-Width

→ Width

3) Content-Type 헤더는 다음의 값들만 허용합니다.

→ application/x-www-form-unlencoded

→ multipart/form-data

→ text/plain

 

Simple Request의 경우 아래와 같이 한 번만 통신합니다.

 

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

 

client는 서버에게 아래와 같은 내용을 보냅니다.

요청 헤더의 Origin을 보면 https://foo.example로부터 요청이 왔다는 것을 알 수 있습니다.

Origin: https://foo.example

 

서버는 이에 대한 응답으로 Access-Control-Allow-Origin 헤더를 전송합니다. 아래의 옵션은 모든 도메인을 허용하는 옵션이며, 특정 도메인만 허용하고 싶을 경우 해당 도메인 주소를 설정하면 됩니다.

Access-Control-Allow-Origin: *

 

2. Preflighted Reques

 

Preflighted Reques는 Simple Request와는 달리, 사전에 OPTIONS method를 통해 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인합니다. Cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송(preflighted) 합니다.

Simple Request의 조건에 만족하지 않은 경우 아래와 같이 Preflighted Request가 발생하게 됩니다.

 

https://developer.mozilla.org/

 

 

첫 번째 통신은 Preflighted 통신입니다.

 

 

Request

Origin: http://foo.example

Response

 

Access-Control-Allow-Origin: https://foo.example

Preflight request가 완료되면 실제 요청을 전송합니다.

 

 

해결 방법

 

1. jsonp 사용

GET 방식 밖에 사용할 수 없기 때문에 길이의 제한이 있습니다.

2. 서버에서 CORS 컨트롤하기

서버 서버 설정으로 요청을 허용하는 방식입니다.

서버 설정에 아래 header를 추가합니다.

(Access-Control-Allow-Origin: * 만 추가해도 되긴 합니다.)

 

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization

 

Tomcat의 경우에는 conf/web.xml에 아래와 같이 filter를 추가하면 됩니다.

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
  </init-param>
  <init-param>
    <param-name>cors.exposed.headers</param-name>
    <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
  </init-param>
  <init-param>
    <param-name>cors.support.credentials</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cors.preflight.maxage</param-name>
    <param-value>10</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

 

[참고사이트]

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

http://tomcat.apache.org/tomcat-8.0-doc/config/filter.html

728x90
loading