본문 바로가기
개발/Programming

CORS 크로스 도메인 이슈 (No 'Access-Control-Allow-Origin' header is present on the requested resource)

by 카루딘 2017. 5. 30.
반응형

참고: https://gist.github.com/kdonald/2232095


스프링에서 CORS 문제를 해결하기 위해 해당 Class를 하나 작성한다.


package com.xxxx.core.filter;


import java.io.IOException;


import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.web.filter.OncePerRequestFilter;


public class CorsFilter extends OncePerRequestFilter {


    @Override

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)

            throws ServletException, IOException {

        response.addHeader("Access-Control-Allow-Origin", "*");

        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())); {

            // CORS "pre-flight" request

            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");

            response.addHeader("Access-Control-Allow-Headers", "Authorization");

            response.addHeader("Access-Control-Max-Age", "1728000");

        }

        filterChain.doFilter(request, response);

    }


}



web.xml 에 아래 필터 추가


    <!-- CORS -->

    <filter>

        <filter-name>cors</filter-name>

        <filter-class>com.xxxx.core.filter.CorsFilter</filter-class>

    </filter>


    <filter-mapping>

        <filter-name>cors</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>



우선 여기 참조

http://ooz.co.kr/232



설명이 이것저것 잡다하게 많은데요, 실제 이를  해결하는 방법은 어렵지 않습니다.

크로스 도메인 요청을 허용할 웹 서버에서 크로스 도메인 이슈를 문제 삼지 않을 도메인을 지정해주면 됩니다.

 

들어오는 모든 요청에 대해 처리해주기 위해 Filter 를 하나 만들어야 될 것 같습니다.

필터(Filter) 이름은 SimpleCORSFilter 로 하기로 하고 SimpleCORSFilter class 를 Filter interface를 구현하여, 생성하도록 합니다.

그리고 이 필터를 웹서비스의 web.xml 에 등록하여 줍니다.

 

 

- web.xml -

<filter>
    <filter-name>cors</filter-name>
    <filter-class>com.company.project.util.domain.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>cors</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

 

 필터 이름은 cors이며, com.company.project.util.domain 패키지 내에 SimpleCORSFilter 클래스를 구현하였습니다.

 모든 URL 패턴(/*)에 대해 필터가 적용되도록 하였습니다.

 

 

 

- SimpleCORSFilter.java -

 

package com.company.project.util.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;

import org.springframework.stereotype.Component;

 

@Component
public class SimpleCORSFilter implements Filter {
 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) res;


        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        
        response.setHeader("Access-Control-Allow-Origin", "*");

     


        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

 

위의 필터는 web.xml 에 정의한 URL 패턴에 의해서 이 웹 서버로 오는 모든 요청이 이 메서드를 지나치게 됩니다. 이 메서드를 한 번 지나고 나면 결과를 내려받는 HTML 페이지 Header에 Access-Control 과 관련된 4개의 라인이 추가되게 됩니다.

 

* response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

 - POST, GET, OPTIONS, DELETE 요청에 대해 허용하겠다는 의미입니다.

 

* response.setHeader("Access-Control-Max-Age", "3600");
 - HTTP Request 요청에 앞서 Preflight Request 라는 요청이 발생되는데, 이는 해당 서버에 요청하는 메서드가 실행 가능한지(권한이 있는지) 확인을 위한 요청입니다. Preflight Request는 OPTIONS 메서드를 통해 서버에 전달됩니다. (위의 Methods 설정에서 OPTIONS 를 허용해 주었습니다.)

 여기서 Access-Control-Max-Age 는 Preflight request를 캐시할 시간입니다. 단위는 초단위이며, 3,600초는 1시간입니다. Preflight Request를 웹브라우저에 캐시한다면 최소 1시간동안에는 서버에 재 요청하지 않을 것입니다.

 

* response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
 이는 표준화된 규약은 아니지만, 보통 AJAX 호출이라는 것을 의미하기 위해 비공식적으로 사용되는 절차입니다. JQuery 또한 AJAX 요청 시, 이 헤더(x-requested-with)를 포함하는 것을 확인하실 수 있습니다. 여기서는 이 요청이 Ajax 요청임을 알려주기 위해 Header 에 x-request-width를 설정합니다. Form을 통한 요청과 Ajax 요청을 구분하기 위해 사용된 비표준 규약지만, 많은 라이브러리에서 이를 채택하여 사용하고 있습니다. (참고로 HTML5 부터는 Form 과 Ajax 요청을 구분할 수 있는 Header가 추가되었습니다.)

 

* response.setHeader("Access-Control-Allow-Origin", "*");
 이 부분이 가장 중요한 부분입니다. * 는 모든 도메인에 대해 허용하겠다는 의미입니다. 즉 어떤 웹사이트라도 이 서버에 접근하여 AJAX 요청하여 결과를 가져갈 수 있도록 허용하겠다는 의미입니다.

 만약 보안 이슈가 있어서 특정 도메인만 허용해야 한다면 * 대신 특정 도메인만을 지정할 수 있습니다.

 

 

response.addHeader("Access-Control-Allow-Origin", "*");

 

대신 

 

response.addHeader("Access-Control-Allow-Origin", "http://www.ozit.co.kr");
response.addHeader("Access-Control-Allow-Origin", "http://abc.ozit.co.kr");
response.addHeader("Access-Control-Allow-Origin", "http://test.ozrank.co.kr");

 

 

이렇게 쓰면

 

www.ozit.co.kr, abc.ozit.co.kr, test.ozrank.co.kr 이렇게 3개의 도메인에 대해서만 크로스 도메인을 허용하겠다는 의미입니다.



출처: http://ooz.co.kr/232 [이러쿵저러쿵]

반응형

'개발 > Programming' 카테고리의 다른 글

jstack 그리고 jconsole - JVM Stack Trace 얻기  (0) 2017.06.07
Jersey File Upload Example  (0) 2017.06.02
Spring + java.servlet.Filter  (0) 2017.05.31
HAProxy로 로드밸런싱  (0) 2017.05.16
래빗엠큐 & 레디스 스터디 1일차.  (0) 2017.05.08