Запросити поле заголовка Access-Control-Allow-Headers не допускається самостійно у передпольотній відповіді


234

Я стикався з проблемами CORS неодноразово і зазвичай можу це виправити, але я хочу реально зрозуміти, побачивши це з парадигми стека MEAN.

Перш ніж я просто додав проміжне програмне забезпечення на свій експрес-сервер, щоб знайти ці речі, але, схоже, є якийсь попередній гак, який помиляється з моїх запитів.

Запит заголовка поля Access-Control-Allow-Headers не дозволений заголовок Access-Control-Allow-Headers у передпольотній відповіді

Я припустив, що можу це зробити:

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

або еквівалент, але це, здається, не виправляє. Я теж звичайно намагався

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

Ще не везе.

Відповіді:


245

Коли ви почнете грати зі спеціальними заголовками запитів, ви отримаєте попередній політ CORS. Це запит, який використовує OPTIONSдієслово HTTP і включає кілька заголовків, в одному з яких є Access-Control-Request-Headersперелік заголовків, які клієнт хоче включити в запит.

Потрібно відповісти на цей попередній політ CORS відповідними заголовками CORS, щоб зробити цю роботу. Одне з яких є насправді Access-Control-Allow-Headers. Цей заголовок повинен містити однакові значення, які Access-Control-Request-Headersмістив заголовок (або більше).

https://fetch.spec.whatwg.org/#http-cors-protocol пояснює цю налаштування більш докладно.


41
Якщо ви користуєтеся Chrome і не впевнені, які заголовки запитуються, скористайтеся Консоллю розробника, Мережа, виберіть дзвінок, що робиться, і ви можете переглянути, які заголовки запитуютьAccess-Control-Request-Headers
Lionel Morrison

5
Важливий варіант консолі розробника. Ви також можете знайти те, що вам потрібно, отримавши доступ до об’єкта запиту на сервері та скидаючи значення для заголовків, а саме значення заголовка для "Access-Control-Request-Headers". Потім скопіюйте та вставте це у свою answer.setHeader ("Access-Control-Allow-Headers", "{paste here}")
Програмне забезпечення Пророків

7
Приклад, будь ласка!
Демодав

5
@Демодайте для мене прикладом цьогоheader("Access-Control-Allow-Headers: Content-Type")
Джошуа Дюксбері

1
@LionelMorrison, використання інструментів хромованого розробника для відповідності заголовків. добре пояснено !!!
Савіна Чандла

119

Це те, що потрібно додати, щоб він працював.

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

Браузер надсилає запит перед польотом (з методом типу OPTIONS), щоб перевірити, чи дозволено доступ до сервісу, розміщеного на сервері, з браузера в іншому домені. У відповідь на запит перед польотом, якщо ви вводите над заголовками, браузер розуміє, що добре робити подальші дзвінки, і я отримаю дійсну відповідь на мій фактичний дзвінок GET / POST. ви можете обмежити домен, до якого надається доступ, використовуючи Access-Control-Allow-Origin "," localhost, xvz.com "замість *. (* надасть доступ до всіх доменів)


7
Ви не можете поєднувати *за ...-Originі trueдля ...-Credentials. Він не провалюється і для незавірених запитів, але він також не працюватиме для облікових запитів. Дивіться посилання, яке я опублікував у своїй відповіді.
Енн

Спасибі Маніш Арора, я використав ваше рішення в моїх api, і воно спрацювало. HttpContext.Response.Headers.Add ("Методи контролю доступу-дозволу", "GET, HEAD, OPTIONS, POST, PUT"); HttpContext.Response.Headers.Add ("Access-Control-Allow-заголовки", "Access-Control-Allow-заголовки", "Походження", "Прийняти", "X-Requested-With", "Content-Type", "Access-Control-Request-method", "доступ" -Контроль-Запит-заголовки "); HttpContext.Response.Headers.Add ("Access-Control-Allow-Origin", " localhost: 4200" );
Ramakrishnankt

1
Це означає, що на сервері все необхідне змінення заголовка відповіді через "передполіт"? Чому? Особливо для ідеально стандартних заголовків? Користуючись HTTP деякий час, мені стало новиною, що потрібно стільки котлован.
Саманта Аткінс

@manish У мене був інший набір значень для Access-Control-Allow-Headers, який не працював. Ваш набір значень зробив. Дякуємо, що заощадили час та розчарування.
azakgaim

Чи є спосіб підкреслити деякі заголовки? Це погана ідея підкреслити всі заголовки? Такі як response.setHeader("Access-Control-Allow-Headers", "*")? Що означає безпека для цього?
Vadorequest

78

Ця проблема вирішена за допомогою

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

Особливо в моєму проекті (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();
});

Оновлення:

Кожен раз, коли помилка: Access-Control-Allow-Headers is not allowed by itself in preflight responseпомилка, ви можете бачити, що не так із інструментом для розробників Chrome :
введіть тут опис зображення

вище помилка відсутня, Content-Typeтому додайте рядок Content-TypeдоAccess-Control-Allow-Headers


1
Це працює не для всіх. Значення заголовків Access-Control-Request-може залежати від середовища. Отримайте доступ до об’єкта запиту на сервері та скиньте значення для заголовка "Access-Control-Request-Headers". Потім скопіюйте та вставте це у свою відповідь.setHeader ("Access-Control-Allow-Headers", "{paste here}")
Програмне забезпечення Пророків

1
Також переконайтеся, що Ви авторизуєте правопис американським способом, а не британською. Це півгодини мого життя я не повернусь. Thx США! [зітхання]
геодезичний

14

Прийнята відповідь в порядку, але у мене виникли труднощі зрозуміти її. Тож ось простий приклад для його уточнення.

У моєму запиті ajax у мене був стандартний заголовок авторизації.

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

Цей код створює помилку у питанні. Що я повинен був зробити на своєму сервері nodejs - це додати Авторизацію у дозволених заголовках:

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

6

Щоб додати до інших відповідей. У мене була така ж проблема, і це код, який я використовував на своєму експрес-сервері для дозволу 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();
  }
});

В основному цей код - це перехоплення всіх запитів і додавання заголовків CORS, а потім продовження моїх звичайних маршрутів. Коли є запит OPTIONS, він відповідає лише заголовками CORS.

EDIT: Я використовував це виправлення для двох окремих серверів експресів nodejs на одній машині. Врешті-решт я вирішив проблему за допомогою простого проксі-сервера.


Дякую! Чи можете ви детальніше пояснити, як ви використовували простий проксі-сервер?
austin_ce

5

Я щойно зіткнувся з цим питанням, в контексті ASP.NET переконайтесь, що ваш Web.config виглядає так:

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

Зауважте значення авторизації для Access-Control-Allow-Headersключа. У мене не було значення авторизації, ця конфігурація вирішує мою проблему.


5

Дуже добре, що я використав це на проекті 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
Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді.
Бадакадабра

4

У Chrome:

Поле запиту заголовка X-Requested-With заборонено за допомогою Access-Control-Allow-Headers у передпольотній відповіді.

Для мене ця помилка спровокована пробілом у URL-адресі цього дзвінка.

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

3

Просто додамо, що ви можете помістити ці заголовки також у файл конфігурації Webpack. Мені вони потрібні були, як і в моєму випадку, коли я запускав 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

Я отримав помилку, заявлену ОП за допомогою Django, React та lib django-cors-headers. Щоб виправити це за допомогою цього стека, виконайте наступне:

У settings.py додайте наведене нижче за офіційною документацією .

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)

2

ця проблема виникає, коли ми робимо власні заголовки для запиту. Цей запит, який використовує HTTP OPTIONSдекілька заголовків і включає його.

Необхідний заголовок для цього запиту Access-Control-Request-Headers, який повинен бути частиною заголовка відповіді і повинен дозволяти запит з усіх джерел. Іноді це потрібно Content-Typeі в заголовку відповіді. Тож ваш заголовок відповіді повинен бути таким -

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

Під час виклику Post API ми надсилаємо дані в орган запиту. Тож якщо ми надішлемо дані, додавши будь-який додатковий заголовок до виклику API. Тоді спочатку відбудеться виклик API OPTIONS, а потім відбудеться поштовий дзвінок. Тому спочатку потрібно обробити виклик OPTION API.

Ви можете вирішити цю проблему, записавши фільтр і всередині, який потрібно перевірити на виклик API виклику опцій та повернути статус 200 ОК. Нижче наведено зразок коду:

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

Якщо ви намагаєтеся додати в заголовки запиту користувальницький заголовок, ви повинні повідомити серверу про те, що дозволено мати певний заголовок. Місце для цього - у класі, який фільтрує запити. У наведеному нижче прикладі назва власного заголовка "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");
    }
}

1

Витративши майже день, я просто з’ясував, що додавання наведених нижче кодів вирішило мою проблему.

Додайте це в Global.asax

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

і в веб-конфігурацію додайте нижче

<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

Я теж зіткнувся з тією ж проблемою в Angular 6. Я вирішив цю проблему, використовуючи код нижче. Додайте код у файл компонент.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

Та сама проблема, з якою я стикався.

Я зробив просту зміну.

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

0

Повідомлення зрозуміло, що "Авторизація" заборонена в API. Встановіть
контроль доступу-дозволу-заголовки: "Тип вмісту, авторизація"


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

Додавання корів у функцію get - це те, що працювало для мене

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.