Поле заголовка запроса 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. Это запрос, который использует HTTP- OPTIONSглагол и включает несколько заголовков, одним из которых является 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
Опция Developer Console является хорошей. Вы также можете найти то, что вам нужно, получив доступ к объекту запроса на сервере и сбросив значения для заголовков, но в частности значение заголовка для «Access-Control-Request-Headers». Затем скопируйте / вставьте это в ваш response.setHeader («Access-Control-Allow-Headers», «{paste here}»)
Пророки программного обеспечения,

7
пример пожалуйста!
Демодава

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

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

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 ("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 -контроль-Request-Headers "); HttpContext.Response.Headers.Add ("Access-Control-Allow-Origin", " localhost: 4200" );
Рамакришнанкт

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 Developer Tool :
введите описание изображения здесь

выше ошибка отсутствует, Content-Typeпоэтому добавьте строку Content-TypeвAccess-Control-Allow-Headers


1
Это не будет работать для всех. Значение для Access-Control-Request-Headers может варьироваться в зависимости от среды. Получите доступ к объекту запроса на сервере и сохраните значения для заголовка «Access-Control-Request-Headers». Затем скопируйте / вставьте это в ваш response.setHeader («Access-Control-Allow-Headers», «{paste here}»)
Пророки программного обеспечения,

1
Также убедитесь, что вы пишете Авторизация по-американски, а не по-британски. Это полчаса моей жизни, я не вернусь. Спасибо США! [вздох]
геоидезическая

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.

РЕДАКТИРОВАТЬ: я использовал это исправление для двух отдельных экспресс-серверов 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 dev.

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

Я получил ошибку, указанную в OP с использованием Django, React и django-cors-headers lib. Чтобы исправить это с этим стеком, сделайте следующее:

В 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 OK. Ниже приведен пример кода:

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

Если вы пытаетесь добавить пользовательский заголовок в заголовки запроса, вы должны сообщить серверу, что конкретный заголовок разрешен. Место для этого находится в классе, который фильтрует запросы. В примере, показанном ниже, пользовательский заголовок имеет имя «тип»:

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. Я решил проблему с помощью приведенного ниже кода. Добавьте код в файл 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

Та самая проблема, с которой я столкнулся.

Я сделал простое изменение.

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

0

Сообщение ясно, что «Авторизация» не допускается в API. Установить
Access-Control-Allow-Headers: «Content-Type, Authorization»


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

Добавление cors в функцию get Это то, что у меня сработало

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.