Access-Control-Allow-Origin CORS 和 HTTPS 重定向问题 (IIS / IISNode / NodeJS)

Access-Control-Allow-Origin issue with CORS and HTTPS redirect (IIS / IISNode / NodeJS)

我有一个分为两部分的网络应用程序:

在尝试逐步将应用程序转换为完全使用 HTTPS 时,我认为最好先转换 back-end。我已经构建了它,以便我可以在 back-end.

上切换 enable/disable HTTPS 的功能

我已经将 back-end 设置为 运行:

当我尝试在本地开发环境中 运行 本地主机下的整个应用程序(前端和 back-end),但使用 HTTP-to-HTTPS 重写(重定向) 规则。之后我在 front-end.

上收到 CORS 错误

简而言之,在我的本地开发环境中,我正在尝试:

在阅读了 CORS 的所有内容数小时后,我根据 this blog post and 调整了 web.config 和 applicationHost.config 以尝试捕获请求来源 header 值.这是他们的样子。

我的 applicationHost.config 包含此部分:

<location path="Default Web Site">
    <system.webServer>
        <rewrite>
            <allowedServerVariables>
                <add name="CAPTURED_ORIGIN" />
                <add name="RESPONSE_Access-Control-Allow-Origin" />
            </allowedServerVariables>
        </rewrite>
    </system.webServer>
</location>

这是我的 Web.config:

<?xml version="1.0" encoding="utf-8"?>
<!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:

     https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->

<configuration>
  <system.webServer>
    <handlers>

      <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
      <add name="iisnode" path="bin/www" verb="*" modules="iisnode" />
    </handlers>   
    <rewrite>
      <rules>
        <rule name="Capture Origin Header"> 
            <match url=".*" /> 
            <conditions> 
              <add input="{HTTP_ORIGIN}" pattern=".+" /> 
            </conditions> 
            <serverVariables> 
              <set name="CAPTURED_ORIGIN" value="{C:0}" /> 
            </serverVariables> 
            <action type="None" /> 
        </rule>

        <!-- HTTP-to-HTTPS redirect -->
                <rule name="Redirect to HTTPS" enabled="true" stopProcessing="true">
                    <match url="(.*)" ignoreCase="true" />
            <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTPS}" pattern="^off$" />
                        <add input="{HTTP_HOST}" pattern="([^/:]*?):[^/]*?" />
            </conditions>                   
                      <action type="Redirect" url="https://{C:1}:3443/{R:0}" appendQueryString="true" redirectType="Temporary" />
                </rule>

        <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
        <rule name="StaticContent">
          <action type="Rewrite" url="public{REQUEST_URI}" />
        </rule>

        <!-- All other URLs are mapped to the node.js site entry point -->
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
          </conditions>
          <action type="Rewrite" url="bin/www" />
        </rule>
      </rules>
      <outboundRules> 
        <rule name="Set-Access-Control-Allow-Origin for known origins"> 
          <match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".+" negate="true" /> 
          <action type="Rewrite" value="{CAPTURED_ORIGIN}" />
        </rule> 
      </outboundRules>       
    </rewrite>

    <!-- Make sure error responses are left untouched -->
    <httpErrors existingResponse="PassThrough" />

  </system.webServer>
  <appSettings>
    <add key="HTTPS_ENABLED" value="true" />
  </appSettings>
</configuration>

NodeJS 应用程序还设置为处理来自 localhost:8000、localhost:3000、localhost:3443(本地 https)和 "null"(转换为字符串)的 CORS . (稍后会详细介绍。)

但是如果我使用这个配置,那么我会在 front-end 中得到以下错误:

XMLHttpRequest cannot load http://localhost:3000/foo/bar/ Response for preflight is invalid (redirect)

我怀疑这是因为 IIS 处理了重定向,但结果是它正在处理带有无效响应(重定向)的预检检查(HTTP 选项)。但是,根据 , and the answer by @sideshowbarker,让我相信 Chrome 的当前版本 59.0.3071.104 应该能够处理来自 CORS 预检选项请求的 HTTP 重定向响应。

如果我从 applicationHost.config 和 HTTP-to-HTTPS 重写和其他规则以及 web.config 中删除服务器变量,然后添加代码以允许 NodeJS 应用程序处理重定向到 HTTPS,那么修改后的应用程序如下所示:

然后出现未知(NodeJS?IIS?)服务器错误,因为请求被取消:

您可以在 chrome://net-internals/#events 中看到取消,即使请求中的 Origin 和响应中的 Access-Control-Allow-Origin headers匹配:

没有有用的错误消息(即使客户端收到了错误消息)这让我相信是 IIS 而不是 NodeJS 取消了请求并且没有发回任何有用的信息。

我最终添加了一个 "null" 条目来处理 CORS 运行 在 NodeJS Lite Server 下(而不是作为实验的 IIS),但我需要这个来 运行在 IIS/IISNode 下。但是,当时的 IIS / IISNode / NodeJS 组合似乎有问题。

我怀疑 "null" 的 Request Origin 很可能是请求的结果,服务器执行重定向,因为您确实有两个请求: - 来自浏览器的原始请求 - 作为重定向结果的请求 当重定向发生时,我假设重定向请求中的来源与原始 URL 不同,并且由于 https://www.w3.org/TR/cors/#generic-cross-origin-request-algorithms 中所述的原因,来源请求 header 在重定向为空。

但是,这并不能解释为什么,当我让 NodeJS 处理重定向时,Origin 请求和 Access-Control-Allow-Origin 响应 header 值都是 null,并且请求仍然被取消。 :-/

最后,如果我消除了 HTTP-to-HTTPS 重定向的任何尝试,那么应用程序在我的开发环境中可以正常工作。

对预检 OPTIONS 本身的响应必须始终是 2xx 响应——例如 200 或 204。对预检本身的响应永远不能是重定向——例如 302。规范禁止这样做。

但是问题中引用的响应显示服务器响应了这样的重定向;因此引用了错误消息。如果浏览器收到对预检 OPTIONS 请求的 3xx 响应,则规范要求浏览器就此停止——将预检视为失败。

所以唯一的解决办法是修复服务器,这样它就不会为 OPTIONS 提供重定向响应。


的问题中描述了重定向和预检的不同场景。在那种情况下,会发生以下情况:

OPTIONS /documents/123   --> 204 (everything okay, please proceed)
GET /documents/123       --> 303 redirect to `/documents/abc`

也就是说,对 OPTIONS 请求本身的响应是 2xx 成功,但对前端代码发送的后续实际请求的响应是 3xx。

对于这种情况,规范 之前 要求浏览器停止并且不允许发出请求的前端代码访问响应,并且浏览器会响应错误:

The request was redirected to 'http://localhost:3000/foo/bar/', which is disallowed for cross-origin requests that require preflight.

请注意,这与问题中针对场景引用的错误消息不同,后者是:

XMLHttpRequest cannot load http://localhost:3000/foo/bar/ Response for preflight is invalid (redirect)

在那种情况下(问题中的那个),情况是这样的:

OPTIONS /documents/123   --> 307 redirect to `/documents/abc`

即对OPTIONS的响应是3xx。规范仍然需要预检失败。

但是其他 disallowed for cross-origin requests that require preflight 案例不再需要失败,浏览器中不应再出现该错误; the spec changed in August 2016 to no longer require it,所有浏览器引擎随后都会更新以匹配该更改。

Chrome 是最后一个实现更新的浏览器,但是 it was fixed in the Chrome sources in December 2016,修复在 Chrome 57.

中发布