请求头字段Access-Control-Allow-Headers不被Access-Control-Allow-Headers允许。

279

我试图通过POST请求将文件发送到我的服务器,但是当发送时会导致以下错误:

请求标头字段Content-Type未被Access-Control-Allow-Headers允许。

因此,我搜索了这个错误并添加了头信息:

$http.post($rootScope.URL, {params: arguments}, {headers: {
    "Access-Control-Allow-Origin" : "*",
    "Access-Control-Allow-Methods" : "GET,POST,PUT,DELETE,OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
}

然后我收到了这个错误:

请求头字段 Access-Control-Allow-Origin 不被 Access-Control-Allow-Headers 允许

于是我在谷歌上搜索,发现唯一类似的问题只提供了一半答案,然后因为不相关而关闭了。我应该添加或删除哪些标头?


2
这些标头是从服务器发送到浏览器的,因此浏览器可以决定是否允许JS解析响应。将它们添加到请求中没有任何价值。 - pellyadolfo
17个回答

296

我曾经遇到同样的问题。在jQuery文档中,我找到了以下内容:

对于跨域请求,将内容类型设置为除 application/x-www-form-urlencodedmultipart/form-datatext/plain 之外的任何值,都会触发浏览器向服务器发送一个预检 OPTIONS 请求。

因此,虽然服务器允许跨域请求,但不允许 Access-Control-Allow-Headers,就会抛出错误。默认情况下,angular 的内容类型是 application/json,这会尝试发送一个 OPTION 请求。尝试覆盖 angular 的默认头或者在服务器端允许 Access-Control-Allow-Headers。这里提供一个 angular 示例:

$http.post(url, data, {
    headers : {
        'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
    }
});

35
这应该是一个可以被接受的答案,比其他答案更具信息量! - Mike Szyndel
1
我想使用multipart/form-data,因为我想上传一些东西。 - Vlado Pandžić
4
如何实现 "or allow Access-Control-Allow-Headers in server end"? - Omar
1
@omar 这取决于你使用的服务器平台。如果是Java,那么其他答案中有例子;如果是PHP,则有一个名为header的函数来设置响应头。 - Fisherman
1
终于,在两天的研究后。我找不到足够的言语来感谢你! - Mekey Salaria
显示剩余6条评论

231
发送POST请求的服务器需要在其响应中包含Access-Control-Allow-Headers头(等等)。从客户端发送请求时添加这些头部是没有效果的。您应该从您的POST请求中删除“Access-Control-Allow-...”头部。
这是因为服务器需要指定它接受跨域请求(以及允许Content-Type请求头等)——客户端不能自行决定给定服务器是否允许CORS。
请求者(Web浏览器)可以通过发送“OPTIONS”请求来测试服务器的同源策略(即不是您打算发送的“POST”或“GET”请求)。如果“OPTIONS”请求的响应包含允许使用您的请求使用的头,来源或方法的“Access-Control-Allow-...”头,则请求者/浏览器将发送您的“POST”或“GET”请求。
(晦涩的注释:) Access-Control-Allow-...的值为“”,而不是列出特定来源、头或允许使用的方法。然而,我使用的旧的Android WebView客户端不支持“”通配符,并需要在OPTIONS请求的响应中列出特定的头信息,以便在Access-Control-Allow-Headers头信息中进行设置。

8
如何在后端设置标题? - user3194367
11
取决于你的后端。 - Felix Kling
26
我想我得跟我的服务器维护人员谈一下。 - user3194367
2
response.addHeader("Access-Control-Allow-Headers", "yourKey"); 响应.添加头("Access-Control-Allow-Headers", "yourKey"); - Mayuresh
2
从请求头中删除 Access-Control-Allow-Origin 字段。 - Alex Montoya
显示剩余7条评论

58

如果这能帮到任何人的话(即使这种方法只是出于开发目的而允许使用),以下是我遇到同样问题时所使用的Java解决方案。 [编辑] 不要使用通配符*,因为这是一个不好的解决方案,如果你真的需要在本地运行,请使用localhost

public class SimpleCORSFilter implements Filter {

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "my-authorized-proxy-or-domain");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
    chain.doFilter(req, res);
}

public void init(FilterConfig filterConfig) {}

public void destroy() {}

}

1
正如多个Access-Control-Request-Headers答案所证明的那样,由于不同的环境,存在明显的差异。对我有效的方法是获取请求对象并转储标题的值,但特别是“Access-Control-Request-Headers”标题的值。然后,将其复制/粘贴到response.setHeader("Access-Control-Allow-Headers", "{paste here}")中。我也在使用Java,但我需要其他值,而且一些在此答案中提到的我不需要。 - Software Prophets
这是一年前为帮助人们并分享线索而提供的部分(如已说,较差)解决方案。我不明白反对的意义,但这是你的自由。这个想法是允许服务器端的头信息,因此当一个OPTION请求被发布时,客户端/浏览器知道哪些头信息是允许的。我承认有点混淆,我的CORS过滤器从那以后改变了很多。作为更好的实践,Access-Control-Allow-Origin永远不应该是*;在我的实现中,它是通过属性设置的。 - lekant
解决方案已经进行了编辑,包括最佳实践。 - lekant

23

你可以通过以下方式在PHP中激活适当的标题:

header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, X-Requested-With");

5
请描述你的答案与其他答案的不同之处。仅发布一些代码并不是非常有帮助的。 - oscfri
2
你是一位摇滚明星,其他答案都深入探讨了技术方面。而你的回答则通过指定应该允许的方法来解决了我的问题! - Daniel ZA
1
@DanielZA 尽管我理解你所说的“其他答案深入了技术方面”,因为你只是想让你的代码运行,但是SO旨在深入挖掘技术细节,因为你应该知道为什么事情能够工作而不仅仅是如何使它们工作。当评论解决方案时,请不要鼓励这种行为。 - nicolasassi

19

发送POST请求的服务器需要在其响应中包含 Content-Type 头。

以下是应包括的典型标头列表,其中包括一个自定义的“X_ACCESS_TOKEN”头:

"X-ACCESS_TOKEN", "Access-Control-Allow-Origin", "Authorization", "Origin", "x-requested-with", "Content-Type", "Content-Range", "Content-Disposition", "Content-Description"

这是你的HTTP服务器需要为你发送请求的Web服务器进行配置。

您可能还希望要求您的服务器管理员公开“Content-Length”标头。

他将认识到这是一个跨域资源共享(CORS)请求,并应该了解制定这些服务器配置的影响。

更多详情请参见:


8
以下内容适用于nodejs:

以下对我有效:

xServer.use(function(req, res, next) {
  res.setHeader("Access-Control-Allow-Origin", 'http://localhost:8080');
  res.setHeader('Access-Control-Allow-Methods', 'POST,GET,OPTIONS,PUT,DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Accept');

  next();
});

1
Access-Control-Allow-Methods的顺序很重要吗? - vini
@vini,我认为这并不重要。 - Ninja Coding

8

如果你正在使用localhost并且遇到问题,可以将PHP设置为以下内容来解决:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type'); 

从您的前端使用:

{headers: {"Content-Type": "application/json"}}

然后,问题就没有了,不再从 localhost 出现!


谢谢,这是在PHP上修复它的正确方法! - Carlos Galeano

5
Asp Net Core中,为了快速启动开发,需要在Startup.csConfigure方法中添加以下内容。
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

4
如果有人在使用express服务器时遇到此问题,请添加以下中间件。
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

4
您尝试设置的标题是响应标题。它们必须由您发出请求的服务器在响应中提供。
它们不应该在客户端上设置。如果权限可以由希望获得权限而不是拥有数据的站点授予,则拥有授予权限的方式将毫无意义。

如何在后端设置头部? - user3194367
@user3194367 — 这取决于你的后端。我不知道你正在向哪个HTTP服务器或编程语言发出请求。 - Quentin
我想我得跟我的服务器管理员谈一谈。 - user3194367

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接