Una solicitud normal
Recientemente, otros deben llamar a una función de nuestro sistema, y la otra parte espera proporcionar una API para que pueda actualizar los datos. Dado que este compañero de clase es un desarrollador de clientes, tiene un código similar al siguiente.
@RequestMapping (método = requestmethod.post, value = "/update.json", produce = mediatype.application_json_value) public @ResponseBody Contacter Update (@RequestBody Contacter Contacterro) {logger.debug ("Obtenga la solicitud de actualización {}", contacerro.Tostring (); if ((Contacterro. == 123) {Contacterro.setUsername ("AdminUpdate-Wangdachui");} return contactterro;}El cliente inicia una solicitud HTTP a través del código para llamarlo. Luego, el estudiante preguntó: esperaba usar llamadas JS a través del navegador, por lo que había un problema de dominio cruzado.
Por qué dominio cruzado
En pocas palabras, el navegador restringe el acceso al código JS en el Sitio A para realizar una solicitud AJAX a la URL en el Sitio B.
Por ejemplo: el siguiente código se puede usar para llamar a la interfaz normalmente a través del código JS bajo este nombre de dominio
(function() {var url = "http://localhost:8080/api/Home/update.json";var data = { "userId": 123, "userName": "wangdachui" };$.ajax({url: url, type: 'POST', dataType: 'json', data: $.toJSON(data), contentType: 'Aplicación/JSON'}). Done (function (resultado) {console.log ("éxito"); console.log (resultado);}). fail (function () {console.log ("error");})}) ()La salida es:
Objeto {userId: 123, nombre de usuario: "AdminUpdate-Wangdachui"}Sin embargo, acceder bajo otros nombres de dominio causará un error:
Opciones http: // localhost: 8080/api/home/update.jsonxmlhttprequest no puede cargar http: // localhost: 8080/api/home/update.json. La respuesta a la solicitud de preplaz no pasa la verificación de control de acceso: no está presente el encabezado de 'Origin' de 'Access-Control-Alow-Origin en el recurso solicitado. El origen 'nulo' no está permitido el acceso. La respuesta tenía el código de estado HTTP 403.
Solución
Jsonp
Usar JSONP para interrogar es una forma relativamente común, pero cuando se ha escrito la interfaz, tanto el servidor como el lado de la llamada deben transformarse y compatibles con la interfaz original, lo cual es demasiado trabajo, por lo que consideramos otros métodos.
Protocolo Cors
Según las referencias: cada página debe devolver un encabezado HTTP llamado 'Origin de acceso de acceso de acceso' para permitir el acceso al sitio en el dominio extranjero. Simplemente puede exponer recursos limitados y acceso limitado al sitio fuera del dominio. En el modo COR, la responsabilidad del control de acceso se puede colocar en manos del desarrollador de la página, no el administrador del servidor. Por supuesto, los desarrolladores de páginas deben escribir un código de procesamiento especial para permitir el acceso al mundo exterior. Podemos entenderlo como: si una solicitud necesita permitir el acceso al dominio cruzado, debe configurar el origen de acceso de acceso de acceso en el encabezado HTTP para decidir a qué sitios permitir acceder. Si necesita permitir que las solicitudes de www.foo.com sean cruzadas, puede configurar: Access-Control- Allow-origin: http://www.foo.com. O Access-Control-Allow-Origin: *. Cors es compatible con la mayoría de los navegadores modernos como parte de HTML5.
Cors tiene los siguientes encabezados comunes
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". iniciar solicitudes de dominio cruzado. "Access-Control-Max-Age" indica que dentro de los 3628800 segundos, no se requieren solicitudes previas a la verificación. El resultado "Access-Control-Allow-Metods" indica que permite obtener, poner, eliminar las solicitudes de dominio "Access-Control-allow-Headers" indica que permite que las solicitudes de dominio cruzado incluyan encabezados de tipo de contenido
Proceso de CORS básico
Primero, se emite una solicitud previa a la luz, que primero emite un método de opciones y una solicitud que contiene el encabezado de "origen" al servidor de recursos. Esta respuesta puede controlar el método de solicitud COR, el encabezado HTTP y la información de verificación. Una solicitud de dominio extranjera real solo se iniciará después de que se permita la solicitud.
Spring MVC es compatible con Cors
La respuesta a la solicitud de preplaz no pasa la verificación de control de acceso: no está presente el encabezado de 'Origin' de 'Access-Control-Alow-Origin en el recurso solicitado. El origen 'nulo' no está permitido el acceso. La respuesta tenía el código de estado HTTP 403.
Desde el mensaje de error anterior, podemos ver que la razón directa es que no hay encabezado de origen de control de acceso de acceso en el encabezado de solicitud. Entonces, nuestra idea directa es agregar este encabezado al encabezado de solicitud. El servidor puede devolver 403, lo que indica que el servidor ha procesado la solicitud.
Interceptor MVC
Primero, configuramos un interceptor para interceptar la solicitud e registrar la información del encabezado de la solicitud.
Debug requestUrl: /api/home/update.json Método de depuración: Opciones Anfitrión del encabezado de depuración: Localhost: 8080 Conexión del encabezado de depuración: Cabezal de depuración de alas Cache-Control: MAX-AGE = 0 Encabezado de depuración Access-Control-Request-Method: Post DeBug Header ORIGE: Null DeBuge Header-Aguent: Mozilla/5.0 (0.0 (N.1. AppleWebkit/537.36 (khtml, como gecko) Chrome/49.0.2623.87 Safari/537.36 Encabezado de depuración Access-Control-Request-Headers: Aception, encabezado de depuración de contenido de contenido Aceptación:*/* Cabeze de debug aceptación: GZIP, Deflate, SDCH Header Debuge Header Aceptar el idioma: zh-cn, zh; q = 0.8, en; q = 0.6
Impresión del inicio de sesión Postthandle descubrió que el estado de la respuesta es 403 en este momento. El seguimiento de los códigos SpringMVC encontró que en org.springframework.web.servlet.dispatcherservlet.DodisPatch, HandleRexecutionChain se obtendrá en función de la solicitud. Después de que SpringMVC adquiere un procesador regular, verificará si se trata de una solicitud de dominio cruzado. Si es así, reemplazará la instancia original.
@OverridePublic HandleRExecutionChain Gethandler (httpservletRequest request) lanza la excepción {object Handler = gethandlerInternal (request); if (handler == null) {handler = getDefaulThandler ();} if (handler == null) {return null;} // bean name o resuelve handler? If ((handler) handlername = (String) Handler; Handler = GetApplicationContext (). GetBean (HandLername);} HandLerExecutionChain EjecutionChain = GethandLerExecutionChain (Handler, request); if (corsutils.isCorsRequest (request)) {Corsconfiguration globalconfig = this.CorsConfigSource.getCorsConfiguration (solicitud); CorSconfiguration handlerConfig = getCorsConfiguration (Handler, request); CorsConfiguration config = (GlobalConfig! = Null? config);} return EjecutionChain;}El método de verificación también es muy simple, es decir, verifique si hay un campo de origen en el encabezado de solicitud.
Public static boolean isCorsRequest (httpservletrequest request) {return (request.getheader (httpheaders.origin)! = null);}La solicitud se entregará a httprequesthandlerAdapter.handle para su procesamiento, y se procesarán diferentes lógicas de acuerdo con el mango. La sentencia anterior se basa en el encabezado de solicitud como una solicitud de dominio cruzado. El controlador obtenido es prefligcho, que se implementa como:
@OverridePublic Void HandLerequest (solicitud httpservletrequest, respuesta httpservletreSponse) lanza ioexception {corsprocessor.processrequest (this.config, request, respuesta);}Continúa haciendo un seguimiento
@OverridePublic Boolean ProcessRequest (CorsConfiguration config, httpservletRequest solicitud, respuesta httpservletResponse) lanza ioexception {if (! Corsutils.isCorsRequest (request)) {return true;} ServletserverHtttPonse ServerResponse = new New ServletserverhttpResponse (respuesta); servletserverhttprequest serverRequest = new ServletServerHttprequest (solicitud); if (webutils.issameOrigin (serverRequest)) {logger.debug ("Skip Cors Processing, la solicitud es una de la misma origen"); return true;} if (ResponseHasCors (ServerResponse)) {logger.deBug ("Skip Cors Processing, Respuesta ya contiene /" Access-Control-e-e-e-Origin /"Header"); Header "); He verdadero;} ROTROW;} ROTRET;} Boolean; preflighTrequest = corsutils.ispreflighTrequest (request); if (config == null) {if (preflighTrequest) {rejectriceChest (servidorResponse); return false;} else {return true;}} return handleInternal (ServerRequest, ServerRessonse, config, Configure);}Este método primero verifica si se trata de una solicitud de dominio cruzado, y si no es así, volverá directamente. Luego verifica si está bajo el mismo dominio, o si tiene el campo de origen de acceso de acceso de acceso en el encabezado de respuesta o si tiene el método de solicitud de control de acceso en la solicitud. Si se cumple la condición de juicio, la solicitud se rechaza.
A partir de esto, sabemos que el cheque se puede aprobar configurando el encabezado de origen de acceso de acceso de acceso de la respuesta antes del cheque. Manejamos la prehandilla en el interceptor. Agregue el siguiente código:
Respuesta.setheader ("Access-Control-Allow-Origin", "*");En este momento, la solicitud de opciones en el navegador devuelve 200. Pero sigue siendo un error:
El tipo de contenido de campo de encabezado de solicitud no está permitido por los cabezales de control de acceso de acceso en la respuesta previa al vuelo.
Notamos que hay encabezados de requisito de control de acceso de acceso: aceptar, tipo de contenido en el encabezado de solicitud, pero este encabezado de solicitud no lo hace. En este momento, el navegador no envía la solicitud según sea necesario. Intente agregarlo a la respuesta:
Respuesta.Setheader ("Access-Control-Allow-Headers", "Origen, X-Requested con, tipo de contenido, Aceptar");Ejecución exitosa: objeto {userId: 123, nombre de usuario: "adminupdate-wangdachui"}.
Hasta ahora: utilizamos el principio de análisis para habilitar SpringMVC para lograr un dominio cruzado, sin ningún cambio en la implementación original y el código del cliente.
SpringMVC 4
Además, en la referencia 2, SpringMVC4 proporciona un método muy conveniente para implementar el dominio cruzado.
Use anotaciones en solicitudes de solicitud. @Crossorigin (Origins = "http: // localhost: 9000")
Implementación global. Herencia de clase de definición WebMVCConfigurerAdapter
La clase pública CorsConfigurerAdapter extiende WebMVCConfigurerAdapter {@OverridePublic Void AddCorsMappings (Registro de Corsregistry) {Registry.AddMapping ("/api/*"). permitidoRigins ("*");}}Inyectar la clase en el contenedor:
<Bean> </reme>
Resumir
Lo anterior es toda la explicación detallada de la implementación de primavera y el procesamiento del código de solicitud de dominio cruzado. Espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!