Permite al navegador emitir solicitudes XMLHttpRequest a servidores de origen cruzado, superando así la limitación de que AJAX solo puede usarse en el mismo origen.
Este artículo presenta el mecanismo interno de CORS en detalle.
(Descripción de la foto: Tomado en Oasis Park en Al Ain, EAU)
1. Introducción
Cors requiere soporte de navegador y servidor. Actualmente, todos los navegadores admiten esta función, y el navegador IE no puede ser más bajo que IE10.
El navegador completa automáticamente todo el proceso de comunicación CORS y no requiere la participación del usuario. Para los desarrolladores, Cors Communication no es diferente de la misma comunicación Ajax de origen, y el código es exactamente el mismo. Una vez que el navegador descubre que AJAX solicita el origen cruzado, agregará automáticamente alguna información de encabezado adicional, y a veces habrá una solicitud adicional, pero el usuario no lo sentirá.
Por lo tanto, la clave para implementar la comunicación CORS es el servidor. Mientras el servidor implementa la interfaz CORS, se puede llevar a cabo la comunicación de origen cruzado.
Dos solicitudes
El navegador divide las solicitudes de CORS en dos categorías: solicitud simple y solicitud no tan simple.
Mientras se cumplan las siguientes dos condiciones principales al mismo tiempo, es una solicitud simple.
(1) El método de solicitud es uno de los siguientes tres métodos:
Poste de la cabeza
(2) La información del encabezado de HTTP no excede los siguientes campos:
Aceptación-LanguageContent-LanguageLast-Event-Idcontent-Type: solo limitado a tres valores application/x-www-form-urlencoded , multipart/form-data , text/plain
Cualquiera que no cumpla con las dos condiciones anteriores al mismo tiempo es una solicitud no simple.
El manejo del navegador de estas dos solicitudes es diferente.
3. Solicitud simple 3.1 Proceso básico
Para solicitudes simples, el navegador emite directamente la solicitud CORS. Específicamente, agregue un campo Origin a la información del encabezado.
El siguiente es un ejemplo. El navegador descubrió que esta solicitud AJAX de origen cruzado era una solicitud simple, y automáticamente agregó un campo Origin a la información del encabezado.
GET /cors HTTP/1.1Origin: http://api.bob.comHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
En la información del encabezado anterior, Origin se utiliza para indicar de qué fuente (protocolo + nombre de dominio + puerto) de la que proviene la solicitud. Según este valor, el servidor decide si acepta la solicitud.
Si la fuente especificada por Origin no está dentro del alcance del permiso, el servidor devolverá una respuesta HTTP normal. El navegador descubrió que la información del encabezado de esta respuesta no contenía el campo Access-Control-Allow-Origin (ver más abajo para más detalles), por lo que se sabía que ocurrió un error y, por lo tanto, se lanzó un error, que fue capturado por la función de devolución de llamada onerror de XMLHttpRequest . Tenga en cuenta que este error no puede ser identificado por el código de estado, porque el código de estado de la respuesta HTTP puede ser 200.
Si el nombre de dominio especificado por Origin está dentro del alcance del permiso, la respuesta devuelta por el servidor tendrá varios campos de encabezado adicionales.
Access-Control-Allow-Origin: http://api.bob.comAccess-Control-Allow-Credentials: trueAccess-Control-Expose-Headers: FooBarContent-Type: text/html; charset=utf-8
Entre la información del encabezado anterior, hay tres campos relacionados con las solicitudes CORS, todos comenzando con Access-Control- .
(1) Access-Control-Allow-Origin
Este campo es obligatorio. Su valor es el valor del campo Origin en el momento de la solicitud, o A * , lo que indica que se acepta la solicitud de cualquier nombre de dominio.
(2) Access-Control-Allable-Credenciales
Este campo es opcional. Su valor es un valor booleano que indica si permitir el envío de cookies. Por defecto, las cookies no están incluidas en las solicitudes de CORS. Establecer en true , lo que significa que el servidor lo permite explícitamente. Las cookies se pueden incluir en la solicitud y enviar juntas al servidor. Este valor solo se puede establecer en true . Si el servidor no envía cookies por el navegador, elimine el campo.
(3) Access-Control-Expose-Headers
Este campo es opcional. Cuando CORS lo solicita, getResponseHeader() del objeto XMLHttpRequest solo puede obtener 6 campos básicos: Cache-Control , Content-Language , Content-Type , Expires , Last-Modified , Pragma . Si desea obtener otros campos, debe especificarlos en Access-Control-Expose-Headers . El ejemplo anterior especifica que getResponseHeader('FooBar') puede devolver el valor del campo FooBar .
3.2 Atributo de insultos
Como se mencionó anteriormente, las solicitudes de CORS no envían cookies e información de autenticación HTTP de forma predeterminada. Si desea enviar cookies al servidor, por un lado, necesita que el servidor esté de acuerdo y especifique el campo Access-Control-Allow-Credentials .
Access-Control-Allow-Credentials: true Por otro lado, el desarrollador debe abrir la propiedad withCredentials en la solicitud AJAX.
var xhr = new XMLHttpRequest();xhr.withCredentials = true;De lo contrario, el navegador no enviará incluso si el servidor acepta enviar cookies. Alternativamente, el servidor requiere que se establezcan cookies, y el navegador no lo manejará.
Sin embargo, si se omite la configuración withCredentials , algunos navegadores aún enviarán cookies juntas. En este momento, puede cerrar explícitamente withCredentials .
xhr.withCredentials = false; Cabe señalar que si desea enviar cookies, Access-Control-Allow-Origin no se puede establecer como un asterisco, y debe especificar un nombre de dominio explícito que sea consistente con la página web solicitada. Al mismo tiempo, las cookies aún siguen la política del mismo origen. Solo se cargarán cookies establecidas con nombres de dominio del servidor. Las cookies de otros nombres de dominio no se cargarán, y document.cookie en el código de página web original (cruzado) no puede leer cookies bajo el nombre de dominio del servidor.
4. Solicitud no simple 4.1 Solicitud previa al vuelo
Una solicitud no simple es una solicitud que tiene requisitos especiales para el servidor, como el método de solicitud es PUT o DELETE , o Content-Type es application/json .
Una solicitud CORS que no es una solicitud simple agregará una solicitud de consulta HTTP antes de la comunicación oficial, que se denomina solicitud de "preplejo".
El navegador primero pregunta al servidor si el nombre de dominio en el que se encuentra la página web actual está en la lista de licencias del servidor y qué verbos y campos de encabezado HTTP se pueden usar. Solo cuando se reciba una respuesta positiva, el navegador emitirá una solicitud formal XMLHttpRequest , de lo contrario se informará un error.
A continuación se muestra un script JavaScript de navegador.
var url = 'http://api.alice.com/cors';var xhr = new XMLHttpRequest();xhr.open('PUT', url, true);xhr.setRequestHeader('X-Custom-Header', 'value');xhr.send();
En el código anterior, el método de solicitud HTTP se PUT y envía una información de encabezado personalizado X-Custom-Header .
El navegador descubrió que esta era una solicitud no simple, por lo que automáticamente emitió una solicitud de "antes de vuelo", que requiere que el servidor confirme que esto se puede solicitar. A continuación se muestra la información del encabezado HTTP para esta solicitud de "preplejo".
OPTIONS /cors HTTP/1.1Origin: http://api.bob.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: X-Custom-HeaderHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0... El método de solicitud utilizado por la solicitud de "preplaz" son OPTIONS , lo que indica que esta solicitud se utiliza para consultar. En la información del encabezado, el campo clave es Origin , que indica de qué fuente proviene la solicitud.
Además del campo Origin , la información del encabezado de la solicitud de "prepleja" incluye dos campos especiales.
(1) Access-Control-Request Method
Este campo se requiere para enumerar qué métodos HTTP se utilizarán para la solicitud CORS del navegador. Se PUT el ejemplo anterior.
(2) Access-Control-Request-Hearters
Este campo es una cadena separada por comas que especifica el campo de información de encabezado adicional que enviará la solicitud CORS del navegador. El ejemplo anterior es X-Custom-Header .
4.2 Respuesta a solicitudes previas a vuelo
Después de que el servidor reciba la solicitud de "preplejo", después de verificar Origin , los campos Access-Control-Request-Method y Access-Control-Request-Headers , confirme que se permiten solicitudes de origen cruzado, y puede responder.
HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:39 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://api.bob.comAccess-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderContent-Type: text/html; charset=utf-8Content-Encoding: gzipContent-Length: 0Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain
En la respuesta HTTP anterior, la clave es el campo Access-Control-Allow-Origin , lo que significa que http://api.bob.com puede solicitar datos. Este campo también se puede establecer en un asterisco para aceptar cualquier solicitud de origen cruzado.
Access-Control-Allow-Origin: *
Si el navegador niega la solicitud de "preplejo", se devolverá una respuesta HTTP normal, pero no hay campos de encabezado relacionados con CORS. En este momento, el navegador determinará que el servidor no está de acuerdo con la solicitud previa al vuelo, por lo que un error es activado y capturado por la función de devolución de llamada onerror del objeto XMLHttpRequest . La consola imprimirá el siguiente mensaje de error.
XMLHttpRequest cannot load http://api.alice.com.Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
Otros campos relacionados con CORS a los que responde el servidor son los siguientes.
Access-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderAccess-Control-Allow-Credentials: trueAccess-Control-Max-Age: 1728000(1) Access-Control-Methods
Este campo es necesario, y su valor es una cadena separada por comas que indica todos los métodos de solicitud de dominio cruzado admitidos por el servidor. Tenga en cuenta que se devuelven todos los métodos compatibles, no solo el solicitado por el navegador. Esto es para evitar múltiples solicitudes de "reflight".
(2) Access-Control-Allumber-Headers
Si la solicitud del navegador incluye Access-Control-Request-Headers , se requiere Access-Control-Allow-Headers . También es una cadena separada por comas que indica que todos los campos de encabezado compatibles con el servidor no se limitan a los campos solicitados por el navegador en "Preflight".
(3) Access-Control-allow-credenciales
Este campo tiene el mismo significado que cuando se solicita de una manera simple.
(4) Access-Control-Max-Age
Este campo es opcional y se utiliza para especificar el período de validez de esta solicitud de reflight, en segundos. En los resultados anteriores, el período de validez es de 20 días (1728,000 segundos), lo que significa que la respuesta se almacena en caché durante 1728,000 segundos (es decir, 20 días). Durante este período, no se requiere otra solicitud previa al vuelo.
4.3 Solicitudes y respuestas normales del navegador
Una vez que el servidor pasa la solicitud de "preplejo", cada vez que la solicitud CORS normal del navegador es la misma que una simple solicitud, habrá un campo de información de encabezado Origin . La respuesta del servidor también tendrá un campo de encabezado Access-Control-Allow-Origin .
A continuación se muestra la solicitud CORS normal del navegador después de la solicitud de "preplejo".
PUT /cors HTTP/1.1Origin: http://api.bob.comHost: api.alice.comX-Custom-Header: valueAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
El campo Origin de la información del encabezado anterior es agregado automáticamente por el navegador.
A continuación se muestra la respuesta normal del servidor.
Access-Control-Allow-Origin: http://api.bob.comContent-Type: text/html; charset=utf-8
En la información del encabezado anterior, el campo Access-Control-Allow-Origin debe incluirse en cada respuesta.
5. Comparación con JSONP
Cors se usa en el mismo propósito que JSONP, pero es más poderoso que JSONP.
JSONP solo admite solicitudes GET , CORS admite todo tipo de solicitudes HTTP. La ventaja de JSONP es que admite navegadores a la antigua y puede solicitar datos de sitios web que no admiten CORS.
(encima)