IIS劫持了CORS Preflight OPTIONS请求

55

我正在进行CORS POST请求,并将Content-Type标头设置为json。这会触发Preflight OPTIONS请求(这是好的和预期的)

这个OPTIONS请求被回复了一个200 OK,但这不是来自我的WebAPI应用程序。

我已经安装了自定义消息处理程序,但它从未被使用过,所以似乎请求在到达ASP.NET之前就已经被IIS响应了。

我找到了几篇关于此主题的文章,它们说:

  1. 确保WebDav已卸载/删除/禁用 - 完成

  2. 确保OPTIONSVerbHandler已被删除/更改为使用aspnet_isapi.dll - 尝试了两种方式

  3. 确保extensionlessURLHandler包括OPTIONS动词 - 完成

然而,我的options请求仍然被劫持。我的意思是,IIS响应了一个200 OK,但在响应中没有包含Access-Control-Allow-Origin头。它没有包含这个头,因为它从未到达我的WebAPI CORS代码,该代码将设置此头。

我能找到的两篇最好的文章听起来像是我的问题:

这里: JQuery stuck at CORS preflight and IIS ghost response

还有这里: http://brockallen.com/2012/10/18/cors-iis-and-webdav/

我尝试在IIS中打开故障请求跟踪(FERB),并将其设置为跟踪所有200状态代码。我从未看到选项请求被记录...不确定这是否意味着FERB不跟踪OPTIONS请求,或者我需要更改FERB设置以使其跟踪OPTIONS请求,或者这是否是我的问题的线索?

这是在IIS 7.5上运行的ASP.NET WebAPI 2.0(也在IIS 8和IISExpress上进行了测试,并具有相同的结果)

无论使用什么浏览器(Chrome、FF和IE都会以相同的方式失败)

我已经尝试了我能找到的所有方法,但仍然无法解决我的问题。

帮助我StackOverflow,你是我的唯一希望。


1
我遇到了类似的问题,请问您能否提供帮助?http://stackoverflow.com/questions/28213210/cors-issue-iis-8-windows-server-2012 - ak1
微软发布IIS CORS模块太晚了 https://learn.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference - Lex Li
16个回答

32

这里有几个你可以尝试的事情,都与web.config有关。首先修改你的模块元素,包括属性runAllManagedModulesForAllRequests="true",如下所示:

<modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDavModule" />
</modules>

然后将您的处理程序设置为以下内容:

<handlers>
   <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
   <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
   <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
   <remove name="WebDav" />
   <remove name="OPTIONSVerbHandler" />
   <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>

这应该能解决问题,但如果没有用的话,作为最后的办法,你可以使用以下代码强制 IIS 输出正确的头部信息:

  <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>

谨慎使用通配符值,您应该将其设置为您的网站将托管的域名。


1
嗨Tom,我尝试了第一个解决方案,仍然没有解决问题。第二个解决方案是我目前的“修复”,但这根本不是解决方法。这是一种hack方法,会破坏我的CORS规则。由于现在我必须允许origin,这不是我想要的。我有多个消费站点需要信任,所以不起作用,单个站点也不起作用。 - Brad Cunningham
绝对的,这是一个折衷方案,并不理想。我自己也遇到了这个问题,并且成功解决了。我相当确定问题出在处理程序映射上,设置路径和动词属性,请参考我的更新回答。如果它有效,请告诉我。 - Tom Hall
2
谢谢你的更新。我已经尝试了这些设置,但没有成功。所有东西都“应该”在我所拥有的条件下工作,但仍然有些不对劲。也许问题更多的是“我如何找出谁在 IIS 中响应这个请求?” - Brad Cunningham
2
有点神秘,不是吗?我刚刚做了一些进一步的阅读,并找到了一个可能有用的片段,将<remove name="OPTIONSVerbHandler"/>添加到<handlers/>部分。 - Tom Hall
1
我尝试过那种方法了。有人说要删除它,也有人说要重新映射一下。我两种方法都尝试过了,但还是没成功。非常感谢到目前为止提供的建议。我相信肯定有解决办法,只是我还没有找到而已。 - Brad Cunningham
显示剩余3条评论

11

在经过4小时的搜索和尝试后,以下方法适用于我:

    <handlers>
        <remove name="OPTIONSVerbHandler" />
        <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="IsapiModule" scriptProcessor="C:\Windows\System32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="None" />
    </handlers>

你使用的是哪个版本的IIS? - Henrik Høyer
IIS 7.5在Windows Server 2008R2 SP1上,ASP经典版。 - Anatoly Alekseev
4
曾与以下内容一起工作: <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="None" />该代码段是用于配置ASP.NET应用程序中的处理程序。它将HTTP OPTIONS动词请求路由到TransferRequestHandler处理程序,以便在服务器上进行处理。此处理程序不需要任何访问权限,并可用于处理未指定资源类型的请求。通配符(*)表示可以将此处理程序应用于应用程序中的所有路径。 - utilsit

7

我尝试了上述所有建议以及在SO上找到的其他建议,但在我的情况下关键是我们在IIS上启用了请求过滤,并且OPTIONS HTTP动词不在允许的动词列表中。一旦我添加它,我就能够解决其余的问题。


5
你把它加在哪里了? - tkit
1
在服务器上的IIS中,选择站点,在功能列表中有一个名为“请求筛选”的选项。然后转到HTTP谓词选项卡,在右侧的操作下选择"允许谓词",输入“OPTIONS”,然后点击确定。 - Brad Germain
这对我来说也是如此。在任何事件或日志中都没有任何信息 - 请求只是404了。有趣的是,在另一个没有默认启用此功能的IIS实例上,它可以正常工作而无需此步骤。 - jrizzo

6

我曾经遇到过同样的问题,以下的web.config设置对我起到了修复作用。

    <modules runAllManagedModulesForAllRequests="false">
      <remove name="FormsAuthenticationModule" />
    </modules>
    <handlers>
      <remove name="OPTIONSVerbHandler" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>

我随后在Application_BeginRequest中手动处理CORS OPTIONS请求。

最初,我使用了这篇博客文章中详细介绍的库来处理CORS请求。但是,我正在开发的产品需要将runAllManagedModulesForAllRequests设置为false。这就是为什么我不得不设置一个自定义实现,但如果您没有这个要求,您应该尝试使用那个库。当我能够将runAllManagedModulesForAllRequests设置为true时,它运行得非常好。


1
是的,我已经在使用Thinktecture了。我的要求与之相反,我必须将runAllManageModulesForAllRequests设置为true。移除FormsAuthModule很有趣,因为我不使用它,所以我会尝试将其移除,虽然我会感到惊讶如果这样就解决了问题。 - Brad Cunningham
很奇怪你在使用Thinktecture库时遇到了这个问题。我在使用它时不需要对处理程序进行任何更改。 - jdehlin

5
在我们的情况下,是IIS中的请求过滤禁用了根Web应用程序级别的OPTIONS动词。打开IIS管理器,点击根应用程序,点击请求过滤,如果选项列表中出现OPTIONS,要么删除它,要么允许该动词。要是我之前就检查好这个问题就好了,浪费了很多时间。

尊敬的先生,您防止了我将笔记本电脑、显示器和 Web 服务器粉碎成数百万个小碎片。如果我可以点赞无数次,我会这么做。谢谢! - phishfordead

1
在我的情况下,我错过了Microsoft.WebApi.Cors软件包。 安装此软件包并在WebApiConfig类中进行如下配置:
 public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();
            config.EnableCors(new EnableCorsAttribute("*","*","*"));
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

在生产环境中使用之前,请对此进行微调,因为您可能不希望任何东西都具有通配符。


正是我正在寻找的。 - Kedar9444

1
这是对我有效的方法:
  <system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>

1

检查IIS上是否安装了URLScan工具。 如果是,请检查以下部分:


;
; The verbs (aka HTTP methods) listed here are those commonly
; processed by a typical IIS server.
;
; Note that these entries are effective if "UseAllowVerbs=1"
; is set in the [Options] section above.
;

GET
HEAD
POST
OPTIONS

0

还有一个情况,也许对某人节省时间。当我使用带有 HttpConfiguration.EnableCors 的配置时,一切正常,但是当我使用 web.config 文件时,它会出现 CORS 错误而失败。在删除了 .vs 文件夹后,它开始工作。


你的回答不清楚。 - MAC

0

我知道这篇文章已经有些年头了,但是我最近也遇到了同样的问题。

在我的情况下,我安装了OWIN和WebAPI的CORS。OWIN的CORS中间件在OPTIONS调用到达WebAPI之前就已经拦截了它。也许这对其他人今后会有所帮助。


10
好的,你针对这个问题采取了什么行动? - tkit
1
我想表达的是(显然不是很清楚),您需要向Owin中间件和WebApi管道都添加CORS。在我的情况下,仅仅做其中之一是不够的。此外,您可能需要重新排列CORS中间件的顺序。例如,如果您在CORS中间件之前有身份验证中间件,那么调用可能会立即被拒绝,因为OPTIONS调用将失败,因为某些东西正在尝试在CORS进程之前处理请求。 - aasukisuki

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