Pole nagłówka żądania Access-Control-Allow-Headers samo w sobie nie jest dozwolone w odpowiedzi podczas inspekcji wstępnej


234

Wiele razy natknąłem się na problemy CORS i zwykle mogę je naprawić, ale naprawdę chcę to zrozumieć, widząc to w paradygmacie stosu MEAN.

Zanim po prostu dodałem oprogramowanie pośrednie na moim serwerze ekspresowym, aby wyłapać te rzeczy, ale wygląda na to, że istnieje pewien rodzaj wstępnego przechwytywania, który pomija moje żądania.

Pole nagłówka żądania Access-Control-Allow-Headers nie jest dozwolone przez Access-Control-Allow-Headers w odpowiedzi podczas inspekcji wstępnej

Zakładałem, że mogę to zrobić:

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

lub odpowiednik, ale wydaje się, że to nie naprawia. Ja też oczywiście próbowałem

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

Wciąż nie ma szczęścia.

Odpowiedzi:


245

Gdy zaczniesz bawić się niestandardowymi nagłówkami żądań, otrzymasz wstępny lot CORS. Jest to żądanie, które korzysta z OPTIONSczasownika HTTP i zawiera kilka nagłówków, z których jeden zawiera Access-Control-Request-Headerslistę nagłówków, które klient chce uwzględnić w żądaniu.

Aby to zadziałało, musisz odpowiedzieć na tę wstępną inspekcję CORS za pomocą odpowiednich nagłówków CORS. Jeden z nich jest rzeczywiście Access-Control-Allow-Headers. Ten nagłówek musi zawierać te same wartości, które Access-Control-Request-Headerszawierał nagłówek (lub więcej).

https://fetch.spec.whatwg.org/#http-cors-protocol wyjaśnia tę konfigurację bardziej szczegółowo.


41
Jeśli używasz Chrome i nie wiesz, o jakie nagłówki są proszone, skorzystaj z Konsoli programisty, wybierz sieć, z której chcesz nawiązać połączenie, i możesz zobaczyć, o które nagłówki ma poprosićAccess-Control-Request-Headers
Lionel Morrison

5
Opcja Konsoli programisty jest dobra. Możesz także znaleźć to, czego potrzebujesz, uzyskując dostęp do obiektu żądania na serwerze i zrzucając wartości dla nagłówków, ale w szczególności wartość nagłówka dla „Kontrola dostępu-nagłówki-żądania”. Następnie skopiuj / wklej to do swojego response.setHeader („Access-Control-Allow-Headers”, „{wklej tutaj}”)
Software Prophets,

7
przykład proszę!
Demodave

5
@Demodave przykładem tego dla mnie byłheader("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury

1
@LionelMorrison, użycie narzędzi chrome dev do dopasowywania nagłówków. dobrze wyjaśnione !!!
Savina Chandla

119

Oto, co musisz dodać, aby działało.

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

Przeglądarka wysyła żądanie inspekcji wstępnej (z metodą typu OPCJE), aby sprawdzić, czy dostęp do usługi hostowanej na serwerze jest możliwy z przeglądarki w innej domenie. W odpowiedzi na żądanie inspekcji wstępnej, jeśli wstrzykujesz powyżej nagłówków, przeglądarka rozumie, że można wykonywać kolejne połączenia, a ja otrzymam prawidłową odpowiedź na moje rzeczywiste wywołanie GET / POST. możesz ograniczyć domenę, do której dostęp jest przyznany, używając Access-Control-Allow-Origin ”,„ localhost, xvz.com ”zamiast *. (* zapewni dostęp do wszystkich domen)


7
Nie można łączyć *za ...-Origini trueza ...-Credentials. Nie zawiedzie w przypadku żądań, które nie są poświadczone, ale nie będzie też działać w przypadku żądań, które nie są poświadczone. Zobacz link, który opublikowałem w mojej odpowiedzi.
Anne,

Dzięki Manish Arora, użyłem twojego rozwiązania w moim API i zadziałało. 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, Type-Type, Access-Control-Request-Method, Access -Control-Request-Headers "); HttpContext.Response.Headers.Add („Access-Control-Allow-Origin”, „ localhost: 4200” );
Ramakrishnankt

1
To znaczy, że po stronie serwera munging nagłówka odpowiedzi jest konieczny z powodu „preflight”? Czemu? Specjalnie dla idealnie standardowych nagłówków? Po dłuższym korzystaniu z protokołu HTTP jest dla mnie nowością, że potrzeba tak dużo płyt grzewczych.
Samantha Atkins

@manish Miałem inny zestaw wartości dla nagłówków Access-Control-Allow-Headers, które nie działały. Twój zestaw wartości tak. Dzięki za oszczędność czasu i frustracji.
azakgaim

Czy istnieje sposób na umieszczenie symboli wieloznacznych w nagłówkach? Czy złym pomysłem jest stosowanie symboli wieloznacznych do wszystkich nagłówków? Takich jak response.setHeader("Access-Control-Allow-Headers", "*")? Jaki jest wpływ tego bezpieczeństwa na bezpieczeństwo?
Vadorequest,

78

Ten problem rozwiązano

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

Szczególnie w moim projekcie (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();
});

Aktualizacja:

Za każdym razem błąd: Access-Control-Allow-Headers is not allowed by itself in preflight responsebłąd można zobaczyć, co złego w narzędziu Chrome dla programistów :
wprowadź opis zdjęcia tutaj

powyżej błędu brakuje, Content-Typewięc dodaj ciąg Content-TypedoAccess-Control-Allow-Headers


1
To nie zadziała dla wszystkich. Wartość nagłówków żądania kontroli dostępu może się różnić w zależności od środowiska. Uzyskaj dostęp do obiektu żądania na serwerze i zrzuć wartości dla nagłówka „Access-Control-Request-Headers”. Następnie skopiuj / wklej to do swojego response.setHeader („Access-Control-Allow-Headers”, „{wklej tutaj}”)
Software Prophets,

1
Upewnij się także, że piszesz Autoryzacja po amerykańsku, a nie po brytyjsku. To pół godziny mojego życia nie wrócę. Dzięki USA! [westchnienie]
geoidesic

14

Przyjęta odpowiedź jest w porządku, ale miałem trudności z jej zrozumieniem. Oto prosty przykład, aby to wyjaśnić.

W mojej prośbie o ajax miałem standardowy nagłówek autoryzacji.

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

Ten kod powoduje błąd w pytaniu. Na moim serwerze nodejs musiałem dodać autoryzację w dozwolonych nagłówkach:

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

6

Aby dodać do innych odpowiedzi. Miałem ten sam problem i jest to kod, którego użyłem na moim serwerze ekspresowym, aby zezwolić na wywołania 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();
  }
});

Ten kod zasadniczo przechwytuje wszystkie żądania i dodaje nagłówki CORS, a następnie kontynuuje moje normalne trasy. Gdy pojawia się żądanie OPCJE, odpowiada tylko nagłówkami CORS.

EDYCJA: Korzystałem z tej poprawki dla dwóch oddzielnych serwerów ekspresowych nodejs na tej samej maszynie. Na koniec naprawiłem problem z prostym serwerem proxy.


Dzięki! Czy możesz wyjaśnić, w jaki sposób wykorzystałeś prosty serwer proxy?
austin_ce

5

Właśnie natrafiłem na ten problem, w kontekście ASP.NET upewnij się, że twój Web.config wygląda następująco:

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

Zwróć uwagę na wartość autoryzacji dla Access-Control-Allow-Headersklucza. Brakowało mi wartości autoryzacji, ta konfiguracja rozwiązuje mój problem.


5

Bardzo dobrze, użyłem tego w projekcie 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");
    });

2
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Badacadabra

4

W Chrome:

Pole nagłówka żądania X-Requested-With nie jest dozwolone przez Access-Control-Allow-Headers w odpowiedzi podczas inspekcji wstępnej.

Dla mnie ten błąd został wywołany przez spację końcową w adresie URL tego wywołania.

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

3

Wystarczy dodać, że możesz umieścić te nagłówki również w pliku konfiguracyjnym Webpack. Potrzebowałem ich tak, jak w moim przypadku, gdy działałem na serwerze deweloperskim 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"
},


2

Otrzymałem błąd zgłoszony przez OP za pomocą Django, React i biblioteki django-cors-headers. Aby naprawić to za pomocą tego stosu, wykonaj następujące czynności:

W settings.py dodaj poniżej zgodnie z oficjalną dokumentacją .

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)

2

ten problem występuje, gdy tworzymy niestandardowy nagłówek żądania. To żądanie, które korzysta z HTTP OPTIONS i zawiera kilka nagłówków.

Wymagany jest nagłówek tego żądania Access-Control-Request-Headers, który powinien być częścią nagłówka odpowiedzi i powinien umożliwiać żądanie od wszystkich źródeł. Czasami potrzebuje Content-Typerównież nagłówka odpowiedzi. Tak powinien wyglądać nagłówek odpowiedzi -

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

1

W wywołaniu API Post przesyłamy dane w treści żądania. Więc jeśli wyślemy dane poprzez dodanie dodatkowego nagłówka do wywołania API. Następnie nastąpi pierwsze OPCJE wywołanie interfejsu API, a następnie zadzwoni post. Dlatego najpierw musisz obsłużyć wywołanie interfejsu OPTION API.

Możesz poradzić sobie z tym problemem, pisząc filtr, w którym musisz sprawdzić wywołanie opcji API wywołania opcji i zwrócić 200 OK. Poniżej znajduje się przykładowy kod:

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
    }

}

1

Jeśli próbujesz dodać niestandardowy nagłówek do nagłówków żądania, musisz poinformować serwer, że określony nagłówek może mieć miejsce. Miejsce do zrobienia znajduje się w klasie, która filtruje żądania. W poniższym przykładzie niestandardowa nazwa nagłówka to „typ”:

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

1

Po spędzeniu prawie dnia dowiedziałem się, że dodanie dwóch poniższych kodów rozwiązało mój problem.

Dodaj to w Global.asax

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

i w konfiguracji sieci dodaj poniżej

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

1

Ja również napotkałem ten sam problem w Angular 6. Rozwiązałem ten problem, używając poniższego kodu. Dodaj kod w pliku 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...
})}

0

Ten sam problem, z którym miałem do czynienia.

Zrobiłem prostą zmianę.

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

0

Wiadomość jest jasna, że ​​„API” nie jest dozwolone w API. Ustaw
nagłówki kontroli dostępu i zezwól: „Typ zawartości, autoryzacja”


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! 🔝 🎉' })
})

Dodanie korków w funkcji get To działało dla mnie

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.