정상적인 요청
최근에 다른 사람들은 우리 시스템의 기능을 호출해야하며 다른 당사자는 데이터를 업데이트 할 수 있도록 API를 제공하기를 희망합니다. 이 급우는 고객 개발자이므로 다음과 유사한 코드가 있습니다.
@RequestMapping (method = requestMethod.post, value = "/update.json", produces = mediaType.application_json_value) public @ResponseBody Contacter Update (@RequestBody Contacter Contacterro) {logger.debug ( "업데이트 요청 {}", Contactertring ()); == 123) {contacterro.setusername ( "inminupdate-Wangdachui");} return contacterro;}클라이언트는 코드를 통해 HTTP 요청을 시작하여 호출합니다. 그런 다음 학생은 다음과 같이 물었습니다.
왜 크로스 도메인
간단히 말해서, 브라우저는 사이트 A의 JS 코드에 대한 액세스를 제한하여 사이트 B에서 AJAX 요청을 요청합니다. 현재 도메인 이름이 www.abc.com 인 경우 현재 환경에서 실행되는 JS 코드는 보안상의 이유로 www.zzz.com 도메인 이름에 따라 리소스에 액세스 할 수 없습니다.
예 : 다음 코드는이 도메인 이름의 JS 코드를 통해 정상적으로 인터페이스를 호출하는 데 사용될 수 있습니다.
(function () {var url = "http : // localhost : 8080/api/home/update.json"; var data = { "userId": 123, "username": "wangdachui"}; $. 'Application/JSON'}). done (function (result) {console.log ( "success"); console.log (result);}). 실패 (function () {console.log ( "error"))}) ()출력은 다음과 같습니다.
Object {userId : 123, 사용자 이름 : "inminupdate-Wangdachui"}}그러나 다른 도메인 이름에서 액세스하면 오류가 발생합니다.
옵션 http : // localhost : 8080/api/home/update.jsonxmlhtttprequest http : // localhost : 8080/api/home/update.json을로드 할 수 없습니다. Preflight 요청에 대한 응답은 액세스 제어 점검을 통과하지 못합니다. 요청 된 리소스에는 '액세스-제어-홀로-오리핀'헤더가 없습니다. 따라서 Origin 'Null'은 액세스 할 수 없습니다. 응답에는 HTTP 상태 코드 403이있었습니다.
해결책
JSONP
JSONP를 사용하여 크로스 도메인을 사용하는 것은 비교적 일반적인 방법이지만 인터페이스가 작성되면 서버와 통화 측면을 모두 원래 인터페이스와 변환하고 호환되어야하므로 다른 방법을 고려합니다.
CORS 프로토콜
참고 문헌에 따르면 : 각 페이지는 외국 도메인의 사이트에 액세스 할 수 있도록 'Access-Control-Ollow-Origin'이라는 HTTP 헤더를 반환해야합니다. 제한된 자원과 제한된 도메인 사이트 액세스를 노출시킬 수 있습니다. COR 모드에서는 액세스 제어의 책임을 서버 관리자가 아닌 페이지 개발자의 손에 넣을 수 있습니다. 물론 페이지 개발자는 외부 세계에 액세스 할 수 있도록 특별 처리 코드를 작성해야합니다. 우리는 다음과 같이 이해할 수 있습니다. 요청에 따라 크로스 도메인 액세스를 허용 해야하는 경우 HTTP 헤더에서 액세스-제어-홀로-오리핀을 설정하여 액세스 할 수있는 사이트를 결정해야합니다. www.foo.com에서 Cross-Domain으로 요청을 허용 해야하는 경우 다음을 설정할 수 있습니다. Access-Control-Ollow-origin : http://www.foo.com. 또는 액세스-제어-홀로-오리진 : *. CORS는 HTML5의 일부로 대부분의 최신 브라우저에서 지원됩니다.
Cors에는 다음과 같은 공통 헤더가 있습니다
Access-Control-allow-origin : http : //foo.orgaccess-control-max-age : 3628800Access-control-allow-methods : get, put, deleteaccess-control-allow-headers : content-type "access-control-allower-origin"은 "http://fo.org"http://fo.org "to"http://fiteate "를 나타냅니다. 요청. "Access-Control-Max-AGE"는 3628800 초 안에 사전 체크 요청이 필요하지 않음을 나타냅니다. "Access-Control-Hallow-Methods"결과는 Get, Put, Out-Domain 요청 "Access-Control-Hallow-Headers"를 허용 함을 나타냅니다. Cross-Domain 요청에 콘텐츠 유형 헤더가 포함될 수 있음을 나타냅니다.
기본 CORS 프로세스
먼저, 프리 플라이트 요청이 발행되며, 먼저 옵션 방법과 리소스 서버의 "원점"헤더가 포함 된 요청을 발행합니다. 이 답변은 COR 요청 방법, HTTP 헤더 및 확인 정보를 제어 할 수 있습니다. 실제 외국 도메인 요청은 요청이 허용 된 후에 만 시작됩니다.
Spring MVC는 CORS를 지원합니다
Preflight 요청에 대한 응답은 액세스 제어 점검을 통과하지 못합니다. 요청 된 리소스에는 '액세스-제어-홀로-오리핀'헤더가 없습니다. 따라서 Origin 'Null'은 액세스 할 수 없습니다. 응답에는 HTTP 상태 코드 403이있었습니다.
위의 오류 메시지에서 직접적인 이유는 요청 헤더에 액세스-제어-홀로-오리핀 헤더가 없기 때문입니다. 따라서 직접 아이디어는이 헤더를 요청 헤더에 추가하는 것입니다. 서버는 403을 반환 할 수있어 서버가 실제로 요청을 처리했음을 나타냅니다.
MVC 인터셉터
먼저, 요청을 가로 채고 요청의 헤더 정보를 기록하도록 인터셉터를 구성합니다.
Debug RequestUrl : /api/home/update.json 디버그 메소드 : 옵션 디버그 헤더 호스트 : LocalHost : 8080 디버그 헤더 연결 : 유지 디버그 헤더 캐시-콘트롤 : 0 Max-age = 0 디버그 헤더 액세스 제목 원산지 : NULL DEBUG 헤드러 사용자 -agent : Mozilla/5.1; AppleWebkit/537.36 (Gecko와 같은 KHTML) Chrome/49.0.2623.87 Safari/537.36 디버그 헤더 액세스 제어-반복 관리자 : 수락, 컨텐츠 유형 디버그 헤더 수락 :*/* 디버그 헤드어 수락 : GZIP, DERLATE, SDCH DEBUG HEADER 허용 : Zh-CN, ZH; Q = 0.8, en; q = 0.6
Posthandle에서 로그 인쇄하면 현재 응답 상태가 403임을 발견했습니다. SpringMVC 코드 추적에 따르면 org.springframework.web.servlet.dispatcherservlet.dodispatch에서 handlerexecutionchain이 요청에 따라 얻을 수 있습니다. SpringMVC가 일반 프로세서를 획득 한 후에는 크로스 도메인 요청 여부를 확인합니다. 그렇다면 원래 인스턴스를 대체합니다.
@overridepublic final handlerexecutionchain gethandler (httpservletrequest request) 예외 {object handler = gethandlerinternal (request); if (handler == null) {handler = getDefaulThandler ();} if (handler == null) {return null) {handler) handlername = (string) handler; handler = getApplicationContext (). getBean (handlername);} handlerexecutionchain executechain = gethandlerexecutionchain (handler, request); if (corsutils.iscorrequest (request)) {corsconfiguration globalconfig = this.corsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);} return executionChain;}확인 방법도 매우 간단합니다. 즉, 요청 헤더에 원점 필드가 있는지 확인하십시오.
공개 정적 부울 iscorsrequest (httpservletrequest 요청) {return (reture.getheader (httpheaders.origin)! = null);}그런 다음 요청은 처리를 위해 httprequesthandleradapter.handle에 양도되며 핸들에 따라 다양한 논리가 처리됩니다. 이전 판단은 요청 헤더를 크로스 도메인 요청으로 기준으로합니다. 획득 된 핸들러는 프리 가이트 맨들러이며 다음과 같이 구현됩니다.
@Overridepublic void handlerequest (httpservletrequest request, httpservletresponse 응답)는 ioexception {corsprocessor.processrequest (this.config, request, response);}계속 후속 조치
@overridepublic boolean processRequest (CorsConfiguration config, httpservletrequest 요청, httpservletResponse 응답)는 ioexception {if (! corsutils.iscorsrequest (recight)) {return;} servletserverhttttpesponse severResponse = new servletserverhttpresponse (응답); servletserverhttprequest serverrequest = new Servletserverhttprequest (요청); if (webutils.issameorigin (serverrequest)) {logger.debug ( "skip cors processing, request는 동일 원산지입니다. preflightrequest = corsutils.ispreflightrequest (요청); if (config == null) {if (preflightrequest) {refectrequest (serverResponse); return false; {return true;}} return handinternal (ServerRequest, ServerResponse, Config, preflightrequest);}};이 방법은 먼저 크로스 도메인 요청 여부를 확인하고 그렇지 않은 경우 직접 돌아갑니다. 그런 다음 동일한 도메인하에 있는지 또는 응답 헤더에 액세스-제어-홀로-오리핀 필드가 있는지 또는 요청에 액세스 제어-퀘스트-메드가 있는지 확인합니다. 판단 조건이 충족되면 요청이 거부됩니다.
이것으로부터 우리는 수표 전에 응답의 액세스-제어-홀로-오리핀 헤더를 설정하여 점검을 통과 할 수 있음을 알고 있습니다. 우리는 인터셉터에서 사전 핸드를 처리합니다. 다음 코드 추가 :
Response.SetHeader ( "액세스-제어-홀로-오리 린", "*");
현재 브라우저의 옵션 요청은 200을 반환하지만 여전히 오류입니다.
요청 헤더 필드 컨텐츠 유형은 프리 플라이트 응답으로 액세스-제어 홀로 헤더가 허용하지 않습니다.
Access-Control-Request-Headers가 있음을 알았습니다 : 요청 헤더에 컨텐츠 유형을 수락하지만이 요청 헤더는 그렇지 않습니다. 현재 브라우저는 필요에 따라 요청을 보내지 않습니다. 응답에 추가 해보십시오.
Response.SetHeader ( "Access-Control-Hallow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
실행 성공 : Object {userId : 123, 사용자 이름 : "inminupDate-Wangdachui"}.
지금까지 : 우리는 분석 원칙을 사용하여 SpringMVC가 원래 구현 및 클라이언트 코드를 변경하지 않고 크로스 도메인을 달성 할 수 있도록합니다.
SpringMVC 4
또한, 참조 2에서 SpringMVC4는 크로스 도메인을 구현하는 매우 편리한 방법을 제공합니다.
RequestMapping에서 주석을 사용하십시오. @Crossorigin (origins = "http : // localhost : 9000")
글로벌 구현. 정의 클래스 상속 webmvcconfigureradapter
공개 클래스 CorsConfigurerAdapter 확장 webmvcconfigureradapter {@overridepublic void addcorsmappings (corsregistry registry) {registry.addmapping ( "/api/*"). allendorigins ( "*");}}클래스를 컨테이너에 주입하십시오.
<bean> </bean>
요약
위의 내용은 스프링 구현 및 처리 크로스 도메인 요청 코드에 대한 자세한 설명입니다. 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!