获取 CORS 未获取标题的 Post 问题
Posted
技术标签:
【中文标题】获取 CORS 未获取标题的 Post 问题【英文标题】:Fetch Post issues with CORS not getting header 【发布时间】:2017-07-21 11:25:29 【问题描述】:这个 CORS 让我再次跪下。我的意思是它可能是如此令人沮丧。请理解,在您对我投反对票之前,我已经查看了有关该主题的所有 500 万篇帖子。我意识到关于这个主题有很多。这是我的 React UI 代码中的 Fetch Post。这是在带有已编译 JS 的 IIS 服务器上运行的,并且只是用于 SPA 的 Index.html。我试图在同一服务器的不同端口上调用 API。这是在 Chrome 和其他现代浏览器中杀死我的预检(在 IE 中似乎很好)。
这里是获取:
return (
fetch(mypost,
method: 'POST',
headers:
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Accept": "application/json",
,
mode: 'cors',
body: JSON.stringify(
name: this.state.value,
)
).then(response =>
if (response.status >= 400)
this.setState(
value: 'no greeting - status > 400'
);
throw new Error('no greeting - throw');
return response.text()
).then(data =>
var myData = JSON.parse(data);
this.setState(
greeting: myData.name,
path: myData.link
);
).catch(() =>
this.setState(
value: 'no greeting - cb catch'
)
)
);
我们都见过的标准预检错误。
Fetch API 无法加载 http://myApiServer:81/values/dui/。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://localhost:82' 不允许访问。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。
这是预检的小提琴:
OPTIONS http://myApiServer:81/values/dui/ HTTP/1.1
Host: myApiServer:81
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:82
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Access-Control-Request-Headers: access-control-allow-origin, content-type
Accept: */*
Referer: http://localhost:82/validator
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
现在我了解到设置 no-cors 基本上会设置一个默认标头,这也不是我想要的,我需要我的 application/json,因为谁不想要 JSON,对吧? :)
我很想就如何解决这个问题提供任何建议。基本上,由于这只是在 IIS 服务器上编译的 javascript 和 index.html,我需要知道处理这些似乎正在发生的预检选项检查的最佳解决方案。
******更新
我尝试添加 webconfig 以强制 IIS 服务器处理预检。似乎它需要在两端,我的 UI 和 API?
这是我的 UI Web.Config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
还有我的 WebApi web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
</customHeaders>
</httpProtocol>
<aspNetCore processPath="dotnet" arguments=".\dui.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true" />
</system.webServer>
</configuration>
我现在得到的只是:
获取 API 无法加载 http://myApiServer:81/values/dui/。预检响应包含无效的 HTTP 状态代码 415。
这里是这个的小提琴。
请求
OPTIONS http://myApiServer:81/values/dui/ HTTP/1.1
Host: myApiServer:81
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:82
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:82/validator
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
和回应
HTTP/1.1 415 Unsupported Media Type
Content-Length: 0
Server: Kestrel
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Date: Thu, 02 Mar 2017 18:35:31 GMT
【问题讨论】:
从您的headers
值中删除 "Access-Control-Allow-Origin": "*",
行。 Access-Control-Allow-Origin
是一个 response 标头。如果你把它放在一个请求中,它除了触发一个预检之外没有任何作用,如果没有被触发的话。
您是否拥有对 http://server:81/values/dui/
的服务器环境的管理员访问权限,以便您可以将其配置为在响应中发送 CORS 响应标头?
@sideshowbarker 我在离开工作之前尝试从我的请求中删除访问控制允许但没有更改。我认为应用程序/Json 可能仍会强制进行预检?我在 IIS 服务器上确实具有管理员访问权限,所以我明天可以尝试任何事情。让我知道。谢谢大哥!
application/json 内容类型的浏览器标头让浏览器做一个预检是的
@sideshowbarker 所以我一直在搞乱 IIS 服务器,更重要的是现在直接使用 web.config 来设置 IIS 中的响应标头。我感觉就像一条追着尾巴的狗。关于 customHeaders,我的 API 和 UI 设置都相同(请参阅 webconfigs 的更新代码)。我的 api 也已经有一些代码来处理 CORS。主要是'services.AddCors();'和'app.UseCors(builder => builder.AllowAnyOrigin());'那一秒似乎导致了这个错误。 (“Access-Control-Allow-Origin”标头包含多个值“*、*”,但只允许一个。)
【参考方案1】:
正如某人在另一篇文章中所建议的那样,假设您没有使用 Nodejs,请对您的服务器端执行等效操作。请注意,我遇到类似问题的客户端是 Reactjs 驱动的,这让我们甚至
app.use(function (req, res, next)
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
);
【讨论】:
【参考方案2】:我已经摸索了 2 个小时,终于找到了适合我的解决方案。如果您和我一样处于同样的情况,我希望我的回答可以帮助您节省时间。由于我可以控制 Web API (aspnet core
) 和客户端 (fetch
),因此我执行了以下操作:
现在我们对 CORS 有了一些了解,请在您的 Startup.cs
文件中执行以下操作:
public void ConfigureServices(IServiceCollection services)
services.AddCors();
public void Configure(IApplicationBuilder app, IHostingEnvironment environment)
app.UseCors(builder =>
builder.WithOrigins("http://yourclient/");
builder.AllowAnyMethod();
builder.AllowAnyHeader();
);
app.UseMvc();
现在在客户端,这样做:
fetch("http://yourapi/api/someresource",
method: "POST",
headers:
"Content-Type": "application/json",
"Access-Control-Request-Headers": "*",
"Access-Control-Request-Method": "*"
,
body: JSON.stringify(data)
)...;
就是这样。
【讨论】:
显然您必须安装Microsoft.AspNetCore.Cors
包才能在服务器上启用 CORS。
@QuantumHive-使用 application/json 您将生成一个预检响应。我很惊讶您不需要服务器上的 webconfig 来处理预检。您是在 IIS 中作为容器还是标准应用程序运行?
@Puerto 我不确定您所说的“容器”或“标准应用程序”是什么意思。也许我应该提到我正在使用dotnet core 1.1
。据我从文档中得知,您唯一需要做的就是使用app.UseCors()
和services.AddCors()
启用CORS。我只是在 IIS 后面使用 Kestrel 服务器。这是从 Visual Studio 模板创建新的 aspnet core
webapp 项目时的默认设置。
你回答了我的问题。您在 IIS 上运行(使用 Kestrel,因为您是 dotnet 核心)。但是您可以将 kestrel 作为跨平台容器化应用程序运行,例如在 OpenShift 中运行。但既然你不是,我很好奇你如何能够绕过在 IIS 服务器上不设置任何东西来处理你的应用程序/json 请求肯定会生成的预检请求。文档可能会说您只需要这两件事,但如果您正在生成预检请求,我认为这并不完全正确。
啊,我明白了。在aspnet core
中,IIS just 将 HTTP 请求委托给 Kestrel。我最近了解到HTTP Modules and Handlers(我们习惯于在 IIS 和 ASP.NET 中使用)不再适用于aspnet core
应用程序。 HTTP 请求由 Kestrel 在我们使用中间件定义的管道中处理(例如app.UserCors()
)。最初,整个 HTTP 管道只是空的。但我不完全确定 IIS 在将请求委托给 Kestrel 之前会执行什么样的业务。【参考方案3】:
我已经为我的 dotnet core webAPI 切换到这个解决方案。我发现它更干净,因为我不需要 webconfig 和 cors 配置,它需要设置得恰到好处才能让 2 一起工作。这消除了 webConfig 中的 cors 内容,因此您只需将其设置在一个地方,即您的 API 应用程序代码本身。
https://www.codeproject.com/Articles/1150023/Enable-Cross-origin-Resource-Sharing-CORS-in-ASP-N
只是对链接中的内容进行简要总结。
添加到 project.json
//Cross Origin Resource Sharing
"Microsoft.AspNetCore.Cors": "1.0.0"
在启动时将其添加到您的 ConfigureServices。
services.AddCors(
options => options.AddPolicy("AllowCors",
builder =>
builder
//.WithOrigins("http://localhost:4456") //AllowSpecificOrigins;
//.WithOrigins("http://localhost:4456",
"http://localhost:4457") //AllowMultipleOrigins;
.AllowAnyOrigin() //AllowAllOrigins;
//.WithMethods("GET") //AllowSpecificMethods;
//.WithMethods("GET", "PUT") //AllowSpecificMethods;
//.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;
.WithMethods("GET", "PUT",
"POST", "DELETE") //AllowSpecificMethods;
//.AllowAnyMethod() //AllowAllMethods;
//.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header");
//AllowSpecificHeaders;
.AllowAnyHeader(); //AllowAllHeaders;
)
);
也可以在启动时配置
//Enable CORS policy "AllowCors"
app.UseCors("AllowCors");
然后在你的控制器中确保你有这些引用:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
using CrossOrigin.WebService.Models.DbEntities;
using Microsoft.EntityFrameworkCore;
最后将属性添加到您的控制器类中。
[EnableCors("AllowCors"), Route("api/[controller]")]
public class ContactController : Controller
【讨论】:
【参考方案4】:所以我要发布这个答案,因为它实际上现在对我有用。这就是我所经历的。我不完全确定为什么,但我会尽力解释我在此过程中学到的东西。如果有人愿意纠正或进一步解释,我会很乐意给予信任和支持。
因此,在 API 中似乎存在 3 层 CORS 感知。
第 1 层
API 本身的代码可能会有一些 CORS 设置,您也应该密切注意这些设置,并且一定会阅读。就我而言,标准位置位于 webApi 的 Startup.cs 中。我的 WebApi 中一直有这些,坦率地说,我认为这就是最初所需要的(我几乎不知道)。
services.AddCors();
app.UseCors(builder => builder.AllowAnyOrigin())
我还在我的 webconfig 中设置了它,这将我们带到:
第 2 层
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
</customHeaders>
我之所以使用它,是因为一位智者说(感谢@sideshowbarker)我的 React UI 中的 Fetch 正在生成一个自定义标头,因此在我的服务器上生成了一个预检响应,因此需要在服务器级别处理该响应.
第 3 层
所以在我的情况下,第 3 层确实不是问题,但在此过程中您必须注意这一点。所以不是在 API 代码中,不是在服务器上,而是在 UI(调用应用程序)本身中。
一般来说,除了"Access-Control-Allow-Origin": "*"
之外,我这里还有正确的东西,这显然不是所有地方都需要的,因为这是响应标头,并且在获取时我指定了请求标头,再次感谢@sideshowbarker。
所以我的 Fetch 请求如下所示:
fetch(mypost,
method: 'POST',
headers:
"Content-Type": "application/json"
,
mode: 'cors',
body: JSON.stringify(
name: this.state.value,
)
)
在我的情况下,主要是因为我是 'context-type: application/json'
导致了预检响应。我想这不是标准的。在当今世界对我来说似乎很标准,但我知道什么。
无论如何,尽管如此,我仍然收到以下消息,坦率地说,这比看到预检错误要好。进步就是进步。
Access-Control-Allow-Origin' 标头包含多个值 '*, *', 但只允许一个。
我在网上发现了一些东西,提到我不需要在两个地方(网络服务器和 API)AllowAnyOrigin
,所以我尝试评论这段代码。
//app.UseCors(builder => builder.AllowAnyOrigin());
得到:
Fetch API 无法加载
http://ApiServer:81/values/dui/
。回应 预检具有无效的 HTTP 状态代码 415
然后根据一些搜索发现一篇文章说最后一个错误可能与标题有关。我回到了 API 源 dotnet Core cors。
https://docs.microsoft.com/en-us/aspnet/core/security/cors
这是一个很好的参考。我应该更加关注这一点。它并没有完全解决我的问题,但我注意到还有另一个构建器可以用于标题,所以我将其插入、重建、发布和 bam,不再有 CORS 问题。一切正常!
这是我插入 API 的代码:
app.UseCors(builder => builder.AllowAnyHeader());
对于第 2 层和第 3 层,我的所有其余代码都保持不变。我将第 1 层的 API 中的 AllowAnyOrigin
构建器注释掉了。
我很抱歉在这里过于冗长,但我发现 CORS 很痛苦,我希望这对某人有所帮助。我会说是时候喝 Coors 了,但我想我们都知道啤酒很糟糕。我想这还是有道理的。
【讨论】:
以上是关于获取 CORS 未获取标题的 Post 问题的主要内容,如果未能解决你的问题,请参考以下文章
获取无效 POST、PATCH 的 CORS 错误 - REST 端点