Fail to load '호출URI': No 'Access-Control-Allow-Origin' header is present in the requested resource. Origin '요청URI' is therefore not allowed access.
원인은 자바스크립트 엔진 표준스펙에 동일출처 정책(SOP:same-origin-policy) 보안 규칙 때문이다.
SOP(Same-origin Policy)
자바스크립트에서 XMLHttpRequest로 외부서버 접근시에는 같은 출처(Same Origin)의 페이지로만 접근이 가능도록 하여 동일한 출처(프로토콜, 호스트명, 포트) 가 모두 일치해야 데이터를 공유할 수 있다.
*출처 Origin 란?
출처란 URI구조에서 프로토콜, 호스트, 포트번호를 말한다.
위와 같이 프로토콜. 도메인. 포트번호 중 하나라도 불일치 하는 경우 SOP정책에 위반하게 된다.
비교예시)
URI 1 | URI 2 | SOP | why ? |
http://cheershena.tistory.com | http://localhost:8080 | X | Host, Port 불일치 |
https://cheershena.tistory.com | https://cheershena.tistory.com | X | Protocol 불일치 |
https://cheershena.tistory.com?id=hena | https://cheershena.tistory.com/20 | O | Protocol, Host, Port 일치 |
https://cheershena.tistory.com:8080 | https://cheershena.tistory.com:8081 | X | Port 불일치 |
하지만 여러 도메인 간의 통신 또는 외부 API등 호출이 많이 일어나는 대규모 웹 어플리케이션에서 이 보안정책은 골치거리이다.
때문에 CORS(Cross-Origin Resource Sharing) 정책이 생겨났다.
받는 서버단에서 외부 요청을 허용하는 경우 ajax요청이 가능해지는 방식이다.
에러를 해결하기 위해 CORS 를 알아보자.
CORS 란? Cross Origin Request Sharing
1. Simple Request 단순요청
단순요청은 요청과 동시에 Cross Origin인지 확인하는데 단순요청의 조건은 다음과 같다.
1) http method : GET , POST , HEAD
2) http header : Accept, Accetp-Language, Content-Language, Content-Type
3) Content-Type : Application/x-www.-form-urlencoded , text/plain, multipart/form-data
위에 해당하면 단순요청을 한다.
2. Preflight Request 사전요청
사전요청은 단순요청과 달리 실제요청을 보내기 전에 요청하려는 경로와 같은 URL에 대해 서버에 OPTIONS메서드로 사전 요청을 먼저 보내고, 응답받는 과정을 통해 해당 요청의 메서드와 헤더에 대해 인식하고 있는지 체크한다. 즉, 거부 및 허용 여부를 확인한다.
2.1 Preflight Request (사전 요청 정보)
1) http method: OPTIONS
2) http header :
Access-Control-Request-Method, //실제요청하려는 메서드
Access-Control-Request-Headers, //실제요청 헤더
Origin //출처 (요청을 보내는 페이지의 도메인)
2.2 Preflight Request (사전 요청에 대한 응답 정보)
1) response header :
Access-Control-Allow-Origin //요청을 허용하는 출처 (* 와일드카드 설정시 모든요청 허용)
Access-Control-Allow-Methods //요청을 허용하는 메서드 (디폴트는 GET / POST)
Access-Control-Allow-Headers //요청을 허용하는 헤더
Access-Control-Max-Age //Preflight 결과를 캐시에 저장하는 시간. 저장된 시간동안 사전요청 암함.
3. Credentialed Request 인증요청
서버단 Filter를 사용하여 외부요청 허용하는 방법
1. CORSFilter.java 생성
//cross domain 설정
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CORSFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Method","POST,GET,OPTIONS,DELETE, PUT");
response.setHeader("Access-Control-Max-Age","3600");
response.setHeader("Access-Control-Allow-Headers","Content-Type,x-requested-with,Authorization,Axxess-Control-Allow-Origin");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
}
<!-- CORSFilter 설정-->
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>com.[클래스경로].CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*<url-pattern> <!--모든요청에 매핑-->
</filter-mapping>
Access-Control-Allow-Origin: *
Access-Control-Allow-Method: POST,GET,OPTIONS, DELETE, PUT
Access-Control-Allow-Headers: Access-Control-Allow-Origin, Contect-Type, x-requdsted-with, Authorization
Access-Control-Max-Age : 3600
Access-Control-Allow-Origin이 * 이므로 모든 요청이 허용되기 때문에 성공적으로 요청이 된다.
단, 테스트 시에는 요긴하게 쓰이지만 실제 운영시에는 보안문제로 특정 출처를 적어주는 것이 좋다.
이렇게 서버측 작업으로 CORS를 해결하였는데, open API를 사용한다던지 외부서버 단 작업이 불가한 경우도 많다.
이럴경우에는 정석적인 해결법은 아니지만 우회하는 방법도 있다.
'Back-end > DEV notes' 카테고리의 다른 글
크롬 개발자모드로 브라우저에서 HTTP POST방식 호출하기 (feat.XMLHttpRequest 객체란?) (0) | 2022.08.24 |
---|---|
git 저장소 주소 repository 변경하기 (1) | 2022.03.13 |
GitHub Pages 활성화 시켜 여러 repository 웹 호스팅하기. (0) | 2022.03.13 |
Markdown Language 마크다운언어 란? + 예제 (0) | 2022.03.13 |
jekyll 지킬이란? (0) | 2022.03.13 |