我被卡住了。 真的... - 已解决。继续阅读:)
场景:我想在这里做正确的事。我依赖 Thinktecture Identitymodel CORS DelegatingHandler 向我的 REST 服务 (ASP.NET Web-API) 添加了 CORS 功能。到目前为止一切顺利。
为了实际测试它是否有效,我执行了以下操作:
- 我设置了一个简单的 HTML 页面并将其发布在与其余服务不同的主机上 (xttp://otherhost/simplewebpage)。该页面使用 JQuery 发出示例请求。代码见下文。
- 接下来,我将我的休息服务设置为不使用 iis express,而是使用它在我的开发机器上运行的完全成熟的实例 (xttp://developmenthost/restservice)。
- 最后但同样重要的是,在我的开发机器上,我打开了 xttp://otherhost/simplewebpage 并触发了 Ajax 请求。执行错误回调告诉我 Chrome 中存在“传输错误”(IE9)或“”(空字符串)。我确保没有与代理相关的连接问题或类似问题。
所以我继续查看 Fiddler 跟踪和 IIS 日志。 Fiddler 说没有 GET/rest/hello 请求,而是一个 OPTIONS/rest/hello 请求——这完全可以预料!然而,对 OPTIONS 请求的响应相当有趣!
整个响应 header 如下所示:
HTTP/1.1 200 OK
Allow: OPTIONS, TRACE, GET, HEAD, POST
Server: Microsoft-IIS/7.5
Public: OPTIONS, TRACE, GET, HEAD, POST
Date: Fri, 15 Feb 2013 14:09:27 GMT
Content-Length: 0
这当然远未达到预期的响应。 有趣的是,请求甚至没有命中我的应用程序中的 Application_BeginRequest()。所以我的应用程序不可能对这个结果负责。我可以在我的 IIS 日志中看到该请求,并且 IIS 添加了 Powered-by-ASP.NET header 。因此它肯定会通过(正确的)IIS 站点。
触发ajax请求的JQuery代码:
function Run()
{
$.ajax({
type: 'GET',
url: url,
dataType: "json",
beforeSend: function(jqXhr) {
jqXhr.setRequestHeader("Authorization", "Basic " + getBasicHttpEncodedString(userName, password));
jqXhr.setRequestHeader("Api-Key", "123");
},
success: successCallback,
error: errorCallback,
timeout: 180*1000
});
}
生成的 OPTIONS 请求如下所示:
OPTIONS http://services.dev13/Rest/Hello HTTP/1.1
Host: developmenthost
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://otherhost/simplewebpage
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17
Access-Control-Request-Headers: accept, origin, api-key, authorization
Accept: */*
DNT: 1
Referer: http://otherhost/simplewebpage
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
...您已经看到了上面的回复。
知道谁准确地回答了我的 OPTIONS 请求吗?还是我的 JQuery 代码有缺陷? 如果我使用例如 Postman(Google Chrome 应用程序)或者如果我在 Fiddler 中伪造请求(这可能是因为他们不进行 CORS 协商 - 没有 OPTIONS 请求),REST 服务工作得很好。
更新 #1: 今天早些时候,我在某处读到禁用 WebDAV 是强制性的,因为它会干扰 OPTIONS 请求。我的 IIS 角色服务 View 告诉我 WebDAV Publishing 未安装。
* 更新#2:* 问题解决了??我挖得更深。 IIS 中注册了一个模块,负责对 OPTIONS 请求的“不受欢迎的(?)”响应。它的名字是“OPTIONSVerbHandler”(处理程序:ProtocolSupportModule)。如果我禁用该模块,请求将传递到我的应用程序。创建了一个更有意义的响应,然后之后是实际的 GET 请求! YAY!
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: http://otherhost/simplewebpage
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept,origin,api-key,authorization
X-AspNet-Version: 4.0.30319
Date: Fri, 15 Feb 2013 15:09:25 GMT
Content-Length: 0
一旦您知道问题出在哪里,您当然会找到大量资源告诉您确保您的 web.config 看起来像这样:-/
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="OPTIONSVerbHandler" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
虽然它在 IE9 中仍然不起作用(“错误:无传输”)。万一有人跟我走同一条路 -> 这是 IE9 的东西:https://stackoverflow.com/a/10232313/1407618
最佳答案
Create PreflightRequestsHandler class where you allow request headers(1) and enable cors before your class(2).
1. public class PreflightRequestsHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Headers.Contains("Origin") && request.Method.Method.Equals("OPTIONS"))
{
var response = new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
// Define and add values to variables: origins, headers, methods (can be global)
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Headers", "content-type");
response.Headers.Add("Access-Control-Allow-Methods", "*");
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
return base.SendAsync(request, cancellationToken);
}
}
2. [EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-Custom-Header")]
关于JQuery 停留在 CORS 预检和 IIS 幽灵响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14897247/