Le champ d'en-tête de demande Access-Control-Allow-Headers n'est pas autorisé par lui-même dans la réponse de contrôle en amont

234

J'ai rencontré des problèmes CORS plusieurs fois et je peux généralement les résoudre, mais je veux vraiment comprendre en voyant cela à partir d'un paradigme de pile MEAN.

Avant j'ai simplement ajouté un middleware sur mon serveur express pour attraper ces choses, mais il semble qu'il y ait une sorte de pré-hook qui dérange mes demandes.

Le champ d'en-tête de demande Access-Control-Allow-Headers n'est pas autorisé par Access-Control-Allow-Headers dans la réponse de contrôle en amont

J'ai supposé que je pouvais faire ceci:

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

ou l'équivalent, mais cela ne semble pas le réparer. J'ai aussi bien sûr essayé

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

Toujours pas de chance.

mibbit
la source

Réponses:

245

Lorsque vous commencez à jouer avec des en-têtes de demande personnalisés, vous obtenez un contrôle en amont CORS. Il s'agit d'une demande qui utilise le OPTIONSverbe HTTP et comprend plusieurs en-têtes, dont l'un Access-Control-Request-Headersrépertorie les en-têtes que le client souhaite inclure dans la demande.

Vous devez répondre à ce contrôle en amont CORS avec les en-têtes CORS appropriés pour que cela fonctionne. Dont l'un est en effet Access-Control-Allow-Headers. Cet en-tête doit contenir les mêmes valeurs que l'en- Access-Control-Request-Headerstête contenait (ou plus).

https://fetch.spec.whatwg.org/#http-cors-protocol explique cette configuration plus en détail.

Anne
la source
41
Si vous utilisez Chrome et que vous ne savez pas quels en-têtes sont demandés, utilisez la Developer Console, Network sélectionnez l'appel en cours et vous pouvez voir quels en-têtes sont demandés parAccess-Control-Request-Headers
Lionel Morrison
5
L'option Developer Console est une bonne option. Vous pouvez également trouver ce dont vous avez besoin en accédant à l'objet de demande sur le serveur et en vidant les valeurs des en-têtes, mais plus précisément la valeur d'en-tête pour "Access-Control-Request-Headers". Ensuite, copiez / collez ceci dans votre response.setHeader ("Access-Control-Allow-Headers", "{coller ici}")
Software Prophets
7
exemple s'il vous plait!
Demodave
5
@Demodave un exemple de cela pour moi étaitheader("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury
1
@LionelMorrison, utilisation d'outils de développement chromés pour faire correspondre les en-têtes. bien expliqué !!!
Savina Chandla
119

Voici ce que vous devez ajouter pour que cela fonctionne.

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");

Le navigateur envoie une demande de contrôle en amont (avec le type de méthode OPTIONS) pour vérifier si le service hébergé sur le serveur est autorisé à accéder à partir du navigateur sur un domaine différent. En réponse à la demande de contrôle en amont si vous injectez les en-têtes ci-dessus, le navigateur comprend qu'il est correct de faire d'autres appels et j'obtiendrai une réponse valide à mon appel GET / POST réel. vous pouvez restreindre le domaine auquel l'accès est accordé en utilisant Access-Control-Allow-Origin "," localhost, xvz.com "au lieu de *. (* accordera l'accès à tous les domaines)

arora maniaque
la source
7
Vous ne pouvez pas combiner *pour ...-Originet truepour ...-Credentials. Il n'échouera pas pour les demandes sans accréditation, mais il ne fonctionnera pas non plus pour les demandes avec accréditation. Voir le lien que j'ai publié dans ma réponse.
Anne
Merci Manish Arora, j'ai utilisé votre solution dans mon API et cela a fonctionné. 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, Content-Access-Control-Request-Method, Access -Control-Request-Headers "); HttpContext.Response.Headers.Add ("Access-Control-Allow-Origin", " localhost: 4200" );
Ramakrishnankt
1
Cela veut dire côté serveur que toute cette munging d'en-tête de réponse est nécessaire à cause du "contrôle en amont"? Pourquoi? Surtout pour les en-têtes parfaitement standard? Après avoir utilisé HTTP pendant un certain temps, c'est une nouvelle pour moi que tant de passe-partout sont nécessaires.
Samantha Atkins
@manish J'avais un ensemble différent de valeurs pour Access-Control-Allow-Headers qui ne fonctionnait pas. Votre ensemble de valeurs l'a fait. Merci d'avoir gagné du temps et de la frustration.
azakgaim
Existe-t-il un moyen de joker certains en-têtes? Est-ce une mauvaise idée de joker tous les en-têtes? Tels que response.setHeader("Access-Control-Allow-Headers", "*")? Quelle est l'implication de sécurité de faire cela?
Vadorequest
78

Ce problème résolu avec

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

Particulier dans mon projet (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();
});

Mettre à jour:

À chaque erreur: Access-Control-Allow-Headers is not allowed by itself in preflight responseerreur, vous pouvez voir ce qui ne va pas avec l' outil de développement Chrome :
entrez la description de l'image ici

l'erreur ci-dessus est manquante, Content-Typealors ajoutez une chaîne Content-TypeàAccess-Control-Allow-Headers

nguyên
la source
1
Cela ne fonctionnera pas pour tout le monde. La valeur des en-têtes de demande de contrôle d'accès peut varier en fonction de l'environnement. Accédez à l'objet de demande sur le serveur et videz les valeurs de l'en-tête "Access-Control-Request-Headers". Ensuite, copiez / collez ceci dans votre response.setHeader ("Access-Control-Allow-Headers", "{coller ici}")
Software Prophets
1
Assurez-vous également que vous épelez l'autorisation de la manière américaine et non de la manière britannique. C'est une demi-heure de ma vie que je ne reviendrai pas. Thx USA! [soupir]
géoidesic
14

La réponse acceptée est correcte, mais j'ai eu du mal à la comprendre. Voici donc un exemple simple pour le clarifier.

Dans ma demande ajax, j'avais un en-tête d'autorisation standard.

$$(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);
}

Ce code produit l'erreur dans la question. Ce que je devais faire sur mon serveur nodejs était d'ajouter une autorisation dans les en-têtes autorisés:

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

Pour ajouter aux autres réponses. J'ai eu le même problème et voici le code que j'ai utilisé dans mon serveur express pour autoriser les appels 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();
  }
});

Ce que ce code fait essentiellement intercepte toutes les demandes et ajoute les en-têtes CORS, puis continue avec mes itinéraires normaux. Lorsqu'il y a une demande OPTIONS, elle ne répond qu'avec les en-têtes CORS.

EDIT: J'utilisais ce correctif pour deux serveurs express nodejs distincts sur la même machine. Finalement, j'ai résolu le problème avec un simple serveur proxy.

Luke Kroon
la source
Merci! Pouvez-vous expliquer comment vous avez utilisé un simple serveur proxy?
austin_ce
5

Je viens de rencontrer ce problème moi-même, dans le contexte d'ASP.NET, assurez-vous que votre Web.config ressemble à ceci:

  <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>

Notez la valeur d'autorisation pour la Access-Control-Allow-Headersclé. Il me manquait la valeur d'autorisation, cette configuration résout mon problème.

Josh Siegl
la source
5

Très bien, je l'ai utilisé sur un projet 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
la source
2
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la manière et / ou la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.
Badacadabra
4

Dans Chrome:

Le champ d'en-tête de demande X-Requested-With n'est pas autorisé par Access-Control-Allow-Headers dans la réponse de contrôle en amont.

Pour moi, cette erreur a été déclenchée par un espace de fin dans l'URL de cet appel.

jQuery.getJSON( url, function( response, status, xhr ) {
   ...
}
user3248255
la source
3

Juste pour ajouter que vous pouvez également mettre ces en-têtes dans le fichier de configuration Webpack. J'en avais besoin comme dans mon cas car j'utilisais le serveur de développement 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
la source
3

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

Kanomdook
la source
2

J'ai reçu l'erreur indiquée par l'OP en utilisant Django, React et la bibliothèque django-cors-headers. Pour le corriger avec cette pile, procédez comme suit:

Dans settings.py, ajoutez ce qui suit selon la documentation officielle .

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)
Eric
la source
2

ce problème se produit lorsque nous créons un en-tête personnalisé pour la demande. Cette demande qui utilise le HTTP OPTIONSet inclut plusieurs en-têtes.

L'en-tête requis pour cette demande est Access-Control-Request-Headers, qui devrait faire partie de l'en-tête de réponse et devrait permettre la demande de toute l'origine. Parfois, il a également besoin Content-Typed'en-tête de réponse. Donc, votre en-tête de réponse devrait être comme ça -

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
la source
1

Dans Post API, nous envoyons des données dans le corps de la demande. Donc, si nous envoyons des données en ajoutant un en-tête supplémentaire à un appel API. Ensuite, le premier appel de l'API OPTIONS se produira, puis le post-appel aura lieu. Par conséquent, vous devez d'abord gérer l'appel de l'API OPTION.

Vous pouvez gérer le problème en écrivant un filtre et à l'intérieur que vous devez vérifier l'appel d'API d'appel d'option et retourner un état 200 OK. Voici l'exemple de code:

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
    }

}
double bip
la source
1

Si vous essayez d'ajouter un en-tête personnalisé sur les en-têtes de demande, vous devez informer le serveur qu'un en-tête spécifique est autorisé à avoir lieu. L'endroit pour le faire est dans la classe qui filtre les demandes. Dans l'exemple ci-dessous, le nom d'en-tête personnalisé est "type":

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
la source
1

Après avoir passé presque une journée, je viens de découvrir que l'ajout des deux codes ci-dessous a résolu mon problème.

Ajoutez ceci dans le Global.asax

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

et dans la configuration Web, ajoutez ce qui suit

<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
la source
1

Moi aussi, j'ai rencontré le même problème dans Angular 6. J'ai résolu le problème en utilisant le code ci-dessous. Ajoutez le code dans le fichier 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 The Programmer
la source
0

Ce même problème auquel j'étais confronté.

J'ai fait un simple changement.

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

Le message est clair que «l'autorisation» n'est pas autorisée dans l'API. Définissez
Access-Control-Allow-Headers: "Content-Type, Authorization"

Rajesh Yadav
la source
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! 🔝 🎉' })
})

Ajouter des cors dans la fonction get est ce qui a fonctionné pour moi

Ayman OUKACHA
la source