Um pedido normal
Recentemente, outros precisam chamar uma função do nosso sistema e a outra parte espera fornecer uma API para que possa atualizar os dados. Como esse colega de classe é um desenvolvedor de clientes, ele tem um código semelhante ao seguinte.
@RequestMapping (Method = requestMethod.post, value = "/update.json", produz = mediatype.application_json_value) public @ResponseBody contacter update (@RequestBody contacter Contacterro) {Logger.Debug ("Get Update {}" ", == 123) {contacterro.setUsername ("adminupdate-wangdachui");} retornar contacterro;}O cliente inicia uma solicitação HTTP através do código para chamá -lo. Então, o aluno perguntou: ele esperava usar chamadas de JS através do navegador, então havia um problema de domínio cruzado.
Por que domínio cruzado
Simplificando, o navegador restringe o acesso ao código JS no Site A para fazer solicitação AJAX ao URL no Site B. Se o nome de domínio atual for www.abc.com, o código JS em execução no ambiente atual não pode acessar os recursos sob o nome de domínio www.zzz.com por motivos de segurança.
Por exemplo: o código a seguir pode ser usado para chamar a interface normalmente através do código JS sob este nome de domínio
(function () {var url = "http: // localhost: 8080/api/home/update.json"; var data = {"userID": 123, "nome de usuário": "wangdachui"}; 'Application/json'}). Done (function (resultado) {console.log ("succcess"); console.log (resultado);}). Fail (function () {console.log ("erro");})}) () () {console.log ("erro");})}) ()A saída é:
Objeto {userID: 123, nome de usuário: "adminupdate-wangdachui"}No entanto, o acesso em outros nomes de domínio causará um erro:
Opções http: // localhost: 8080/api/home/update.jsonxmlhttprequest não pode carregar http: // localhost: 8080/api/home/update.json. Resposta à solicitação de pré-voo não passa a verificação de controle de acesso: Não está presente o cabeçalho 'acesso-controle-arel-origin' no recurso solicitado. A origem 'nula', portanto, não é permitida acesso. A resposta teve o código de status HTTP 403.
Solução
JSONP
O uso do JSONP para domínio cruzado é uma maneira relativamente comum, mas quando a interface foi escrita, o servidor e o lado da chamada precisam ser transformados e compatíveis com a interface original, o que é um pouco demais, por isso consideramos outros métodos.
Protocolo CORS
De acordo com as referências: cada página precisa retornar um cabeçalho HTTP chamado 'Access-Control-Alow-Origin' para permitir o acesso ao site no domínio estranho. Você pode apenas expor recursos limitados e acesso limitado ao site fora do domínio. No modo COR, a responsabilidade do controle de acesso pode ser colocada nas mãos do desenvolvedor da página, não o administrador do servidor. Obviamente, os desenvolvedores de páginas precisam escrever código de processamento especial para permitir o acesso ao mundo exterior. Podemos entendê-lo como: se uma solicitação precisar permitir o acesso ao domínio cruzado, você precisará definir o Access-Control-Alow-Origin no cabeçalho HTTP para decidir quais sites permitir o acesso. Se você precisar permitir que solicitações de www.foo.com sejam cross-domain, poderá definir: Access-Control-allow-origin: http://www.foo.com. Ou acesso-controle-arel-origin: *. O CORS é apoiado na maioria dos navegadores modernos como parte do HTML5.
CORS tem os seguintes cabeçalhos comuns
Access-Control-Allow-Origin: http://foo.orgAccess-Control-Max-Age: 3628800Access-Control-Allow-Methods: GET, PUT, DELETEAccess-Control-Allow-Headers: content-type "Access-Control-Allow-Origin" indicates that it allows "http://foo.org" to initiate cross-domain solicitações. "Access-Control-Max-Iage" indica que, em 3628800 segundos, não são necessárias solicitações de pré-verificação. O resultado "Access-Control-Arn-Methods" indica que ele permite obter, colocar e excluir solicitações de domínio "Access-Control-arlow-headers" indica que ele permite que solicitações de domínio cruzado incluam cabeçalhos do tipo conteúdo
Processo básico dos CORs
Primeiro, uma solicitação de pré -voo é emitida, que primeiro emite um método de opções e uma solicitação que contém o cabeçalho "Origin" para o servidor de recursos. Esta resposta pode controlar o método de solicitação COR, o cabeçalho HTTP e as informações de verificação. Uma solicitação real de domínio estrangeiro será iniciada apenas após a solicitação ser permitida.
Spring MVC suporta CORS
Resposta à solicitação de pré-voo não passa a verificação de controle de acesso: Não está presente o cabeçalho 'acesso-controle-arel-origin' no recurso solicitado. A origem 'nula', portanto, não é permitida acesso. A resposta teve o código de status HTTP 403.
A partir da mensagem de erro acima, podemos ver que o motivo direto é que não há cabeçalho de origem-controle-arigin no cabeçalho da solicitação. Portanto, nossa idéia direta é adicionar este cabeçalho ao cabeçalho da solicitação. O servidor pode retornar 403, indicando que o servidor realmente processou a solicitação.
MVC Interceptor
Primeiro, configuramos um interceptador para interceptar a solicitação e registrar as informações do cabeçalho da solicitação.
Debug requesturl: /api/home/update.json Método de depuração: Opções de depuração Host: localhost: 8080 Conexão de cabeçalho de depuração: cache de cabeçalho de depuração Keep-alive): pós-depurador/cubar de débug. AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 DEBUG header access-control-request-headers:accept, content-type DEBUG header accept:*/* DEBUG header accept-encoding:gzip, deflate, sdch DEBUG header Aceitar-Language: ZH-CN, Zh; Q = 0,8, en; q = 0,6
Imprimir o login Posthandle descobriu que o status da resposta é 403 no momento. Os códigos Springmvc de rastreamento descobriram que em org.springframework.web.servlet.dispatcherServlet.dodispatch, HandlerexecutionCain será obtido com base na solicitação. Depois que a SpringMVC adquire um processador regular, ele verificará se é uma solicitação de domínio cruzado. Nesse caso, ele substituirá a instância original.
@OverridePublic Final HandlerexecutionChain Gethandler (solicitação httpServletRequest) lança exceção {manipulador de objetos = gethandlerinternal (request); if (handler == null) {handler = getDefaulthandler ();} if (handler == null? handlername = (string) handler; handler = getApplicationContext (). getBean (nome do handlern);} handlerexecutionChain ExecutionChain = gethandlerexecutionChain (manipulador, solicitação); if (corsutils.iscorsrequest (request)) {corsconfiguration); this.CorsConfigSource.getCorsConfiguration (request); corsConfiguration HandlerConfig = getCorsConfiguration (manipulador, request); corsConfiguration config = (globalConfig! = Null? config);} Retornar ExecutionChain;}O método de verificação também é muito simples, ou seja, verifique se existe um campo de origem no cabeçalho da solicitação.
public estático booleano iSCorsRequest (solicitação httpServletRequest) {return (request.getheader (httpheaders.origin)! = null);}A solicitação será entregue a httprequesthandleratapter.handle para processamento, e diferentes lógicas serão processadas de acordo com o identificador. O julgamento anterior é baseado no cabeçalho da solicitação como uma solicitação de domínio cruzado. O manipulador obtido é o pré -fludidor, que é implementado como:
@OverridePublic void handleRequest (solicitação httpServletRequest, httpServletResponse) lança ioexception {corsprocessor.processRequest (this.config, solicitação, resposta);}Continue a acompanhar
@OverridePublic Boolean ProcessRequest (Config CORSConfiguration, solicitação httpServletRequest, resposta httpServletResponse) lança ioexception {if (! Corsutils.iscorsRequest (request)) {return true; ServletServerhttpResponse (Response); ServletServerHttPrequest ServerRequest = new ServletServerHttPrequest (request); if (webutils.issameorigin (serverRequest)) {Logger.debug ("Pule o processamento do CORS, a solicitação é a mesma origem um"); retorna true;} if (ResponseHascors (serverResponse)) {Logger.debug ("Skips Processing, RESPONSE") pré -flaghtRequest = corsutils.ispreflightReCerest (request); if (config == null) {if (prellightReCerest) {rejecrequest (servidorResponse); retorna false;} else {return}}} retorna o handleInternal (serverrequest, servidor -resposta, cig, config,Este método primeiro verifica se é uma solicitação de domínio cruzado e, se não for, ele retornará diretamente. Em seguida, verifica se ele está no mesmo domínio ou se possui o campo de origem-controle de acesso no cabeçalho da resposta ou se possui o método de acesso à solicitação de acesso na solicitação. Se a condição de julgamento for atendida, a solicitação será rejeitada.
A partir disso, sabemos que a verificação pode ser passada definindo o cabeçalho da resposta de acesso ao controle de acesso à resposta antes da verificação. Lidamos com a pré -manuseio no interceptador. Adicione o seguinte código:
Response.setheader ("Access-Control-Alow-Origin", "*");No momento, a solicitação de opções no navegador retorna 200. Mas ainda é um erro:
A solicitação de cabeçalho de cabeçalho do tipo conteúdo de conteúdo não é permitida pelos cabeçalhos de controle de acesso à resposta de pré-voo.
Percebemos que existem cabeçalhos de controle de acesso a acesso: aceitar, do tipo conteúdo no cabeçalho da solicitação, mas esse cabeçalho de solicitação não. No momento, o navegador não envia a solicitação conforme necessário. Tente adicioná -lo à resposta:
Response.setheader ("Access-Control-Alow-headers", "Origin, x-requestado com, tipo conteúdo, aceitar");Execução bem-sucedida: objeto {userID: 123, nome de usuário: "adminupdate-wangdachui"}.
Até agora: usamos o princípio de análise para permitir que a SpringMVC atinja os domínios cruzados, sem nenhuma alteração na implementação original e no código do cliente.
Springmvc 4
Além disso, na referência 2, o SpringMVC4 fornece um método muito conveniente para implementar o domínio cruzado.
Use anotações no requestMapping. @Crossorigin (origens = "http: // localhost: 9000")
Implementação global. Classe de definição Herança webmvcConfigureRAdApter
classe pública corsConfigureRAdApter estende o webmvcConfigureRAdApter {@OverridePublic void AddCorsMappings (CORSREGISTRO Registry) {Registry.addmapping ("/API/*"). Permitido ("*");}}}}}}Injete a classe no contêiner:
<Bean> </ Bean>
Resumir
O exposto acima é toda a explicação detalhada da implementação da primavera e do processamento do código de solicitação de domínio cruzado. Espero que seja útil para todos. Amigos interessados podem continuar se referindo a outros tópicos relacionados neste site. Se houver alguma falha, deixe uma mensagem para apontá -la. Obrigado amigos pelo seu apoio para este site!