JQuery坚持CORS预检和IIS幽灵响应

时间:2013-02-15 14:51:03

标签: jquery http asp.net-web-api cors

我被困了。 严重...... - 已解决。请继续阅读:)

情景:我正在尝试做正确的事情。我依靠Thinktecture Identitymodel CORS DelegatingHandler将CORS功能添加到我的REST服务(ASP.NET Web-API)。到目前为止一切都很好。

要实际测试它是否正常工作,我会执行以下操作:

  1. 我设置了一个简单的HTML页面并将其发布在与其他服务不同的主机上( xttp:// otherhost / simplewebpage )。该页面使用JQuery来发出样本请求。代码见下文。
  2. 接下来,我将我的休息服务设置为不使用iis express,而是在我的开发机器上运行它的完整实例( xttp:// developmenthost / restservice )。
  3. 最后但并非最不重要的是在我的开发机器上,我打开了xttp:// otherhost / simplewebpage并触发了Ajax请求。执行错误回调告诉我Chrome中存在“传输错误”(IE9)或“”(空字符串)。我确保没有代理相关的连接问题或类似的东西。
  4. 所以我出去看了一下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
    

    这当然远不及预期的反应。 有趣的部分是,Request甚至没有在我的应用程序中点击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(谷歌Chrome应用程序)或者我在Fiddler伪造请求(这可能是因为他们没有进行CORS协商 - 没有OPTIONS请求),REST服务就可以正常工作。

    更新#1: 今天早些时候,我在某处看到禁用WebDAV是强制性的,因为它会干扰OPTIONS请求。我的IIS角色服务视图告诉我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中仍然不起作用(“错误:没有传输”)。如果有人和我一样走了同一条路 - &gt;这是一个IE9的东西:https://stackoverflow.com/a/10232313/1407618

3 个答案:

答案 0 :(得分:0)

你的答案在这里: https://gist.github.com/mathieucarbou/1114981

基本上,IE对于角色有一些非常具体的警告和陷阱。我开始自己写一次,但后来我找到了mathieucarbou的解决方案,并认为他的更好。

这可能比你想要的解决方案稍微重一点,但是对于跨浏览器的支持,我发现使用“自定义解决方案”尽可能地使用IE来接受IE是可以接受的。

答案 1 :(得分:0)

选中此set-access-control-allow-origin-in-web-api。这可能会对您有所帮助。

答案 2 :(得分:0)

  

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