在预检响应中本身不允许请求标头字段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")
})

仍然没有运气。

Answers:


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
莱昂内尔·莫里森

5
开发者控制台选项是一个很好的选择。您还可以通过访问服务器上的请求对象并转储标头的值(特别是“ Access-Control-Request-Headers”的标头值)来找到所需的内容。然后,将其复制/粘贴到您的response.setHeader(“ Access-Control-Allow-Headers”,“ {paste here}”)
软件先知

7
请举个例子!
Demodave

5
@Demodave对我来说,一个例子是header("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury

1
@LionelMorrison,使用chrome开发工具来匹配标头。很好的解释!
Savina Chandla '17

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
不能同时使用*...-Origintrue...-Credentials。对于非凭证式请求,它不会失败,但对于凭证式请求,它也不起作用。请参阅我在答案中发布的链接。
安妮(Anne)

谢谢Manish Arora,我在我的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 -Control-Request-Headers“);HttpContext.Response.Headers.Add(“ Access-Control-Allow-Origin”,“ localhost:4200”);
Ramakrishnankt

1
这就是说,由于“预检”,服务器端所有这些响应标头都是必需的吗?为什么?特别是对于完美的标准接头?使用HTTP已有一段时间对我来说是一个新闻,需要这么多样板。
萨曼莎·阿特金斯

@manish对于无效的Access-Control-Allow-Header,我有一组不同的值。您的一组价值观确实做到了。感谢您节省时间和沮丧。
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-TypeAccess-Control-Allow-Headers


1
这并不适合所有人。Access-Control-Request-Header的值可能会因环境而异。获取对服务器上请求对象的访问,并转储“ Access-Control-Request-Headers”标头的值。然后,将其复制/粘贴到您的response.setHeader(“ Access-Control-Allow-Headers”,“ {paste here}”“)
软件先知

1
另外,请确保您使用的是美国式而非英国式的授权。那是我生命中的半个小时,我不会回来。谢谢美国![叹气]
大地测量学'18

14

可以接受的答案是可以的,但是我很难理解。因此,这里有一个简单的例子来阐明它。

在我的ajax请求中,我有一个标准的Authorization标头。

$$(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 express服务器。最后,我用一个简单的代理服务器解决了这个问题。


谢谢!您能否详细说明如何使用简单的代理服务器?
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密钥的授权值。我错过了Authorization值,此配置解决了我的问题。


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
尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
Badacadabra

4

在Chrome中:

飞行前响应中的Access-Control-Allow-Headers不允许请求标头字段X-Requested-With。

对我来说,此错误是由此调用的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

我收到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调用添加任何额外的标头来发送数据。然后,将首先进行OPTIONS API调用,然后进行后调用。因此,您必须先处理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

如果试图在请求标头上添加自定义标头,则必须让服务器知道允许发生特定标头。这样做是在筛选请求的类中。在下面显示的示例中,自定义标头名称为“ 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中也遇到了同样的问题。我使用下面的代码解决了这个问题。将代码添加到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
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函数中添加cors对我有用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.