JQuery在CORS飞行前和IIS重影响应时卡住



我被卡住了 说真的-已解决。读取时间:)

场景:我正在努力做正确的事情。我依靠ThinktectureIdentitymodelCORSDelegatingHandler将CORS功能添加到我的REST服务(ASP.NETWeb-API)中。到目前为止还不错。

为了实际测试它是否工作,我做了以下操作:

  1. 我建立了一个简单的HTML页面,并将其发布在与rest服务不同的主机上(xttp://otherhost/simplewebpage)。页面使用JQuery进行示例请求。代码见下文
  2. 接下来,我将我的rest服务设置为不使用iis-express,而是使用它在我的开发机器上运行的完整实例(xttp://developmenthost/restservice
  3. 最后但同样重要的是,在我的开发机器上,我打开了xttp://otherhost/simplewebpage并激发Ajax请求。执行错误回调,告诉我Chrome中存在"传输错误"(IE9)或"(空字符串)。我确保没有代理相关的连接问题或类似的问题

所以我继续查看Fiddler跟踪和IIS日志。Fiddler说没有GET/rest/hello请求,而是OPTIONS/rest/hello请求——这完全是意料之中的事!然而,对OPTIONS请求的回应相当有趣!

整个响应标头如下所示:

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标头。。所以它肯定会通过(右侧)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角色服务视图告诉我WebDAV发布未安装

*更新#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.NETFrameworkv4.0.30319aspnet_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.NETFramework64v4.0.30319aspnet_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

创建PreflightRequestsHandler类,在其中允许请求头(1),并在类(2)之前启用cors。

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")]

您的答案如下:https://gist.github.com/mathieucarbou/1114981

基本上,IE对cors有一些非常具体的警告和陷阱。我曾经自己写过一篇,但后来我找到了马蒂厄卡布的解决方案,并认为他的解决方案更好。

这可能是一个比你想要的更重的解决方案,但对于跨浏览器支持,我发现用"自定义解决方案"来打击IE是可以接受的。

检查这个set-access-control-allow-origin-in-web-api。这可能会对你有所帮助。

最新更新