El campo de encabezado de solicitud Access-Control-Allow-Headers no está permitido por sí mismo en la respuesta previa al vuelo

234

Me he encontrado con problemas de CORS varias veces y generalmente puedo solucionarlo, pero realmente quiero entender al ver esto desde un paradigma MEAN stack.

Antes simplemente agregué middleware en mi servidor express para detectar estas cosas, pero parece que hay algún tipo de preenganche que está enviando errores a mis solicitudes.

El campo de encabezado de solicitud Access-Control-Allow-Headers no está permitido por Access-Control-Allow-Headers en la respuesta previa al vuelo

Supuse que podía hacer esto:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Headers","*")
})

o el equivalente pero esto no parece solucionarlo. También, por supuesto, intenté

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Headers","Access-Control-Allow-Headers")
})

Aún sin suerte.

mibbit
fuente

Respuestas:

245

Cuando comience a jugar con encabezados de solicitud personalizados, obtendrá una verificación previa de CORS. Esta es una solicitud que utiliza el OPTIONSverbo HTTP e incluye varios encabezados, uno de los cuales es Access-Control-Request-Headersenumerar los encabezados que el cliente desea incluir en la solicitud.

Debe responder a esa verificación previa CORS con los encabezados CORS apropiados para que esto funcione. Uno de los cuales es de hecho Access-Control-Allow-Headers. Ese encabezado debe contener los mismos valores que Access-Control-Request-Headerscontenía el encabezado (o más).

https://fetch.spec.whatwg.org/#http-cors-protocol explica esta configuración con más detalle.

Ana
fuente
41
Si usa Chrome y no está seguro de qué encabezados se solicitan, use la Consola de desarrollador, seleccione la llamada de red y podrá ver qué encabezados solicitaAccess-Control-Request-Headers
Lionel Morrison
55
La opción de la Consola de desarrollador es buena. También puede encontrar lo que necesita al obtener acceso al objeto de solicitud en el servidor y volcar los valores para los encabezados, pero específicamente el valor del encabezado para "Access-Control-Request-Headers". Luego, copie / pegue esto en su respuesta. SetHeader ("Access-Control-Allow-Headers", "{paste here}")
Software Prophets
77
ejemplo por favor!
Demodave
55
@Demodave un ejemplo de esto para mí fueheader("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury
1
@LionelMorrison, uso de herramientas de desarrollo de Chrome para hacer coincidir los encabezados. Bien explicado !!!
Savina Chandla
119

Esto es lo que necesita agregar para que funcione.

response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");

El navegador envía una solicitud de verificación previa (con el tipo de método OPTIONS) para verificar si se puede acceder al servicio alojado en el servidor desde el navegador en un dominio diferente. En respuesta a la solicitud de verificación previa si inyecta los encabezados anteriores, el navegador comprende que está bien hacer más llamadas y obtendré una respuesta válida a mi llamada GET / POST real. puede restringir el dominio al que se otorga el acceso utilizando Access-Control-Allow-Origin "," localhost, xvz.com "en lugar de *. (* otorgará acceso a todos los dominios)

arora varonil
fuente
77
No puedes combinar *por ...-Originy truepara ...-Credentials. No fallará para las solicitudes sin credenciales, pero tampoco funcionará para las solicitudes con credenciales. Vea el enlace que publiqué en mi respuesta.
Anne
Gracias Manish Arora, utilicé tu solución en mi API y funcionó. HttpContext.Response.Headers.Add ("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT"); HttpContext.Response.Headers.Add ("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access -Control-Request-Headers "); HttpContext.Response.Headers.Add ("Access-Control-Allow-Origin", " localhost: 4200" );
Ramakrishnankt
1
¿Esto está diciendo del lado del servidor que toda esta mezcla de encabezado de respuesta es necesaria debido a "verificación previa"? ¿Por qué? ¿Especialmente para encabezados perfectamente estándar? Habiendo usado HTTP por un tiempo, es una novedad para mí que se necesita tanta repetitiva.
Samantha Atkins el
@manish Tenía un conjunto diferente de valores para Access-Control-Allow-Headers que no funcionaban. Su conjunto de valores lo hizo. Gracias por ahorrar tiempo y frustración.
azakgaim
¿Hay alguna forma de comodín para algunos encabezados? ¿Es una mala idea poner comodines en todos los encabezados? Tales como response.setHeader("Access-Control-Allow-Headers", "*")? ¿Cuál es la implicación de seguridad de hacer esto?
Vadorequest
78

Este problema resuelto con

 "Origin, X-Requested-With, Content-Type, Accept, Authorization"

Particular en mi proyecto (express.js / nodejs)

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
  next();
});

Actualizar:

Cada vez error: Access-Control-Allow-Headers is not allowed by itself in preflight responseerror, puedes ver qué está mal con la herramienta de desarrollador de Chrome :
ingrese la descripción de la imagen aquí

falta el error anterior, Content-Typeasí que agregue una cadena Content-TypeaAccess-Control-Allow-Headers

nguyên
fuente
1
Esto no funcionará para todos. El valor de Access-Control-Request-Headers puede variar según el entorno. Obtenga acceso al objeto de solicitud en el servidor y descargue los valores para el encabezado "Access-Control-Request-Headers". Luego, copie / pegue esto en su respuesta. SetHeader ("Access-Control-Allow-Headers", "{paste here}")
Software Prophets
1
También asegúrese de estar deletreando Autorización a la manera americana, no a la manera Britsh. Eso es media hora de mi vida, no volveré. Thx USA! [suspiro]
geoidesic
14

La respuesta aceptada está bien, pero tuve dificultades para entenderla. Así que aquí hay un ejemplo simple para aclararlo.

En mi solicitud ajax tenía un encabezado de autorización estándar.

$$(document).on('ajaxStart', function(e){
var auth_token = localStorage.getItem(SB_TOKEN_MOBILE);
if( auth_token ) {
    var xhr = e.detail.xhr;

    xhr.setRequestHeader('**Authorization**', 'Bearer ' + auth_token);
}

Este código produce el error en la pregunta. Lo que tenía que hacer en mi servidor nodejs era agregar Autorización en los encabezados permitidos:

res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,**Authorization**');
usuario732456
fuente
6

Para agregar a las otras respuestas. Tuve el mismo problema y este es el código que utilicé en mi servidor express para permitir llamadas REST:

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'URLs to trust of allow');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  if ('OPTIONS' == req.method) {
  res.sendStatus(200);
  } else {
    next();
  }
});

Lo que básicamente hace este código es interceptar todas las solicitudes y agregar los encabezados CORS, luego continuar con mis rutas normales. Cuando hay una solicitud de OPCIONES, solo responde con los encabezados CORS.

EDITAR: Estaba usando esta solución para dos servidores express nodejs separados en la misma máquina. Al final solucioné el problema con un servidor proxy simple.

Luke Kroon
fuente
¡Gracias! ¿Puedes explicar cómo usaste un servidor proxy simple?
austin_ce
5

Acabo de encontrarme con este problema, en el contexto de ASP.NET, asegúrese de que su Web.config se vea así:

  <system.webServer>
<modules>
  <remove name="FormsAuthentication" />
</modules>

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <!--<remove name="OPTIONSVerbHandler"/>-->
  <remove name="TRACEVerbHandler" />
  <!--
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  -->
</handlers>

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
  </customHeaders>
</httpProtocol>

Observe el valor de autorización para la Access-Control-Allow-Headersclave. Me faltaba el valor de Autorización, esta configuración resuelve mi problema.

Josh Siegl
fuente
5

Muy bien, usé esto en un proyecto de silex

$app->after(function (Request $request, Response $response) {
        $response->headers->set('Access-Control-Allow-Origin', '*');
        $response->headers->set("Access-Control-Allow-Credentials", "true");
        $response->headers->set("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
        $response->headers->set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    });
Al Kativo
fuente
2
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a cómo y / o por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta.
Badacadabra
4

En cromo:

El campo de encabezado de solicitud X-Solicitado-Con no está permitido por Access-Control-Allow-Headers en la respuesta previa al vuelo.

Para mí, este error fue provocado por un espacio final en la URL de esta llamada.

jQuery.getJSON( url, function( response, status, xhr ) {
   ...
}
usuario3248255
fuente
3

Solo para agregar que puede colocar esos encabezados también en el archivo de configuración de Webpack. Los necesitaba como en mi caso, ya que estaba ejecutando el servidor de desarrollo webpack.

devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Credentials": "true",
      "Access-Control-Allow-Methods": "GET,HEAD,OPTIONS,POST,PUT",
      "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization"
},
Janne
fuente
3

res.setHeader ('Access-Control-Allow-Headers', '*');

Kanomdook
fuente
2

Recibí el error que el OP declaró usando Django, React y la lib django-cors-headers. Para solucionarlo con esta pila, haga lo siguiente:

En settings.py agregue lo siguiente según la documentación oficial .

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)
Eric
fuente
2

Este problema ocurre cuando hacemos un encabezado personalizado para la solicitud. Esta solicitud utiliza HTTP OPTIONSe incluye varios encabezados.

El encabezado requerido para esta solicitud es Access-Control-Request-Headers, que debe ser parte del encabezado de respuesta y debe permitir la solicitud de todo el origen. A veces también se necesita Content-Typeen el encabezado de respuesta. Entonces su encabezado de respuesta debería ser así:

response.header("Access-Control-Allow-Origin", "*"); // allow request from all origin
response.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin, X-Requested-With, Content-Type, Accept, Authorization");
Sai prateek
fuente
1

En la llamada Post API estamos enviando datos en el cuerpo de la solicitud. Entonces, si enviaremos datos agregando cualquier encabezado adicional a una llamada API. Luego, se realizará la primera llamada de OPTIONS API y luego se realizará la llamada posterior. Por lo tanto, primero debe manejar la llamada OPTION API.

Puede manejar el problema escribiendo un filtro y dentro de eso debe verificar la opción de llamada a la llamada API y devolver un estado 200 OK. A continuación se muestra el código de muestra:

package com.web.filter;

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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.Response;

public class CustomFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
        if (httpRequest.getMethod().equalsIgnoreCase("OPTIONS")) {
            response.setStatus(Response.SC_OK);
        }
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
        // TODO
    }

    public void destroy() {
        // Todo
    }

}
doble pitido
fuente
1

Si está intentando agregar un encabezado personalizado en los encabezados de solicitud, debe informar al servidor que se permite que tenga lugar un encabezado específico. El lugar para hacerlo es en la clase que filtra las solicitudes. En el ejemplo que se muestra a continuación, el nombre del encabezado personalizado es "tipo":

public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin",  request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, Authorization, type ");
        response.setHeader("Access-Control-Expose-Headers","Authorization");
    }
}
Kristina Mojanovska
fuente
1

Después de pasar casi un día, descubrí que agregar los dos códigos a continuación resolvió mi problema.

Agregue esto en Global.asax

protected void Application_BeginRequest()
{
  if (Request.HttpMethod == "OPTIONS")
  {
    Response.StatusCode = (int)System.Net.HttpStatusCode.OK;             
    Response.End();
  }
}

y en la configuración web agregue el siguiente

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />        
    <add name="Access-Control-Allow-Methods" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
  </customHeaders>
</httpProtocol>
Biruk Belihu
fuente
1

Yo también enfrenté el mismo problema en Angular 6. Resolví el problema usando el siguiente código. Agregue el código en el archivo component.ts.

import { HttpHeaders } from '@angular/common/http';

headers;

constructor() {
    this.headers = new HttpHeaders();
    this.headers.append('Access-Control-Allow-Headers', 'Authorization');
}

getData() {
    this.http.get(url,this.headers). subscribe (res => {
    // your code here...
})}
Karthi el programador
fuente
0

Ese mismo problema que estaba enfrentando.

Hice un cambio simple.

  <modulename>.config(function($httpProvider){
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
Shashikant Pandit
fuente
0

El mensaje es claro que "Autorización" no está permitido en la API. Establezca
Access-Control-Allow-Headers: "Content-Type, Authorization"

Rajesh Yadav
fuente
0
const express = require('express')
const cors = require('cors')
const app = express()

app.get('/with-cors', cors(), (req, res, next) => {
  res.json({ msg: 'WHOAH with CORS it works! 🔝 🎉' })
})

Agregar cors en la función get es lo que funcionó para mí

Ayman OUKACHA
fuente