简体   繁体   English

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

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

I have a web application that is in two parts:我有一个分为两部分的 Web 应用程序:

  • The "front-end" based in Angular (under Chrome) running on localhost:8000基于 Angular(在 Chrome 下)在 localhost:8000 上运行的“前端”
  • The "back-end" based in ExpressJS/NodeJS, running on localhost:3000基于 ExpressJS/NodeJS 的“后端”,运行在 localhost:3000

In trying to gradually convert the application to entirely use HTTPS, I thought it would be better to convert the back-end, first.在尝试逐步将应用程序转换为完全使用 HTTPS 时,我认为首先转换后端会更好。 I have built it so that I can toggle the ability to enable/disable HTTPS on the back-end.我已经构建了它,以便我可以在后端切换启用/禁用 HTTPS 的能力。

I have set up the back-end to run:我已经设置后端运行:

  • With two bindings under IIS: http and https在 IIS 下有两个绑定:http 和 https
  • The NodeJS application under IISNode. IISNode 下的 NodeJS 应用程序。

The problem comes about when I attempt to run the entire application (front- and back-end) under localhost in a local development environment, but with an HTTP-to-HTTPS rewrite (redirect) rule.当我尝试在本地开发环境中的 localhost 下运行整个应用程序(前端和后端)时,问题就出现了,但使用的是 HTTP-to-HTTPS 重写(重定向)规则。 After that I receive CORS errors on the front-end.之后,我在前端收到 CORS 错误。

In short, in my local development environment, I am attempting:简而言之,在我的本地开发环境中,我正在尝试:

基本应用

After reading on all things CORS for hours, I adjusted the web.config and the applicationHost.config based upon this blog post and this StackOverflow article in an attempt to capture the Request Origin header value.在阅读了 CORS 的所有内容数小时后,我根据这篇博文和这篇 StackOverflow 文章调整了 web.config 和 applicationHost.config,以尝试捕获 Request Origin 标头值。 Here is what they look like.这是他们的样子。

My applicationHost.config contains this section:我的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>

And here is my Web.config :这是我的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>

The NodeJS application is also set up to handle CORS from localhost:8000, localhost:3000, localhost:3443 (local https), and "null" (converted to a string). NodeJS 应用程序还设置为处理来自 localhost:8000、localhost:3000、localhost:3443(本地 https)和“null”(转换为字符串)的 CORS。 (More on that, later.) (稍后会详细介绍。)

But if I use this configuration, then I get the following error in the front-end:但是如果我使用这个配置,那么我会在前端得到以下错误:

XMLHttpRequest cannot load http://localhost:3000/foo/bar/ Response for preflight is invalid (redirect) XMLHttpRequest 无法加载http://localhost:3000/foo/bar/预检响应无效(重定向)

I suspect this is because IIS handled the redirect, but as a result it is handling the preflight check (HTTP OPTIONS) with an invalid response (redirect).我怀疑这是因为 IIS 处理了重定向,但结果它正在处理带有无效响应(重定向)的预检检查(HTTP OPTIONS)。 However, according to this StackOverflow article , and the answer by @sideshowbarker , leads me to believe that the current version of Chrome, 59.0.3071.104, should be able to handle the HTTP redirect response from the CORS preflight OPTIONS request.但是,根据这篇 StackOverflow 文章@sideshowbarker的回答,我相信 Chrome 的当前版本 59.0.3071.104 应该能够处理来自 CORS 预检 OPTIONS 请求的 HTTP 重定向响应。

If I remove the server variables from the applicationHost.config and the HTTP-to-HTTPS rewrite and other rules and from the web.config, and then add code to allow the NodeJS application to handle the redirect to HTTPS, then the revised application looks like this:如果我从 applicationHost.config 和 HTTP-to-HTTPS 重写和其他规则以及 web.config 中删除服务器变量,然后添加代码以允许 NodeJS 应用程序处理重定向到 HTTPS,那么修改后的应用程序看起来像这样:

修改后的应用程序

Then it appears an unknown (NodeJS? IIS?) server error occurs because the request is cancelled:然后出现一个未知的(NodeJS?IIS?)服务器错误,因为请求被取消:

Chrome 开发工具网络 1

Chrome 开发工具网络 2

You can see the cancellation in chrome://net-internals/#events even though the Origin in the request and the Access-Control-Allow-Origin in the response headers match:即使请求中的 Origin 和响应标头中的 Access-Control-Allow-Origin 匹配,您也可以在 chrome://net-internals/#events 中看到取消:

Chrome 网络内部

There is no useful error message (even though one is being received by the client) which leads me to believe that it is IIS and not NodeJS that is cancelling the request and sending back no useful information.没有有用的错误消息(即使客户端收到一条错误消息),这让我相信是 IIS 而不是 NodeJS 取消了请求并且没有发回任何有用的信息。

I ended up adding a "null" entry to handle CORS when running under the NodeJS Lite Server (and not IIS as an experiment), but I need this to run under IIS/IISNode.在 NodeJS Lite 服务器(而不是 IIS 作为实验)下运行时,我最终添加了一个“null”条目来处理 CORS,但我需要它在 IIS/IISNode 下运行。 However, there seems to be a problem with then IIS / IISNode / NodeJS combination.但是,然后 IIS / IISNode / NodeJS 组合似乎存在问题。

I suspect that the Request Origin of "null" is most likely the result of a request, where the server performs a redirect, because you really have two requests: - The original request from the browser - The request that is the result of the redirect When the redirect occurs, I am hypothesizing that the origin in the redirected request is not that same as the original URL, and for the reasons stated in https://www.w3.org/TR/cors/#generic-cross-origin-request-algorithms , the Origin request header within the redirect is null.我怀疑“null”的请求来源很可能是服务器执行重定向的请求的结果,因为您确实有两个请求:-来自浏览器的原始请求-作为重定向结果的请求发生重定向时,我假设重定向请求中的来源与原始 URL 不同,原因在https://www.w3.org/TR/cors/#generic-cross-origin -request-algorithms ,重定向中的 Origin 请求标头为空。

However, that doesn't explain, why, when I let NodeJS handle the redirect that the Origin request and the Access-Control-Allow-Origin response header values are both null and the request still gets cancelled.但是,这并不能解释,为什么当我让 NodeJS 处理重定向时 Origin 请求和 Access-Control-Allow-Origin 响应标头值都为 null 并且请求仍然被取消。 :-/ :-/

Finally, if I eliminate any attempt at HTTP-to-HTTPS redirect, then the application works without issue in my development environment.最后,如果我消除了任何 HTTP 到 HTTPS 重定向的尝试,那么该应用程序在我的开发环境中可以正常工作。

The response to the preflight OPTIONS itself must always be a 2xx response—eg, 200 or 204. The response to the preflight itself can never be a redirect—eg, 302. The spec prohibits that.对预检OPTIONS本身的响应必须始终是 2xx 响应,例如 200 或 204。对预检本身的响应永远不能是重定向,例如 302。规范禁止这样做。

But the response cited in the question shows a server responding with such a redirect;但是问题中引用的响应显示服务器使用这种重定向进行响应; hence the error message cited.因此引用的错误消息。 If a browser gets a 3xx response to a preflight OPTIONS request, the spec requires that the browser stop right there—to consider the preflight as failing.如果浏览器收到对预检 OPTIONS 请求的 3xx 响应,则规范要求浏览器在此停止——将预检视为失败。

So the only solution is to fix the server so it doesn't give a redirect response for that OPTIONS .因此,唯一的解决方案是修复服务器,使其不会对该OPTIONS给出重定向响应。


There's a different scenario with redirects and preflights that's described in the question at CORS request with Preflight and redirect: disallowed.CORS request with Preflight and redirect: disallowed 的问题中描述了重定向和预检的不同场景。 Workarounds? 解决方法? . . In that scenario, this is what occurs:在这种情况下,会发生以下情况:

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

That is, the response to the OPTIONS request itself is a 2xx success, but the response to the subsequent actual request that the frontend code is sending is a 3xx.即对OPTIONS请求本身的响应是2xx成功,但是对前端代码正在发送的后续实际请求的响应是3xx。

For that case, the spec previously required browsers to stop and not allow the frontend code making the request to have access to the response, and browsers would respond with an error:对于这种情况,规范之前要求浏览器停止并且不允许发出请求的前端代码访问响应,并且浏览器会以错误响应:

The request was redirected to ' http://localhost:3000/foo/bar/ ', which is disallowed for cross-origin requests that require preflight.该请求被重定向到“ http://localhost:3000/foo/bar/ ”,这对于需要预检的跨域请求是不允许的。

Note that's different than the error message cited for the scenario in the question, which is:请注意,这与为问题中的场景引用的错误消息不同,即:

XMLHttpRequest cannot load http://localhost:3000/foo/bar/ Response for preflight is invalid (redirect) XMLHttpRequest 无法加载http://localhost:3000/foo/bar/预检响应无效(重定向)

In that scenario (the one in the question), this is instead what occurs:在那种情况下(问题中的那个),这就是发生的情况:

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

That is, the response to the OPTIONS is 3xx.也就是说,对OPTIONS的响应是 3xx。 The spec still requires a preflight failure for that.该规范仍然需要为此进行预检失败。

But that other disallowed for cross-origin requests that require preflight case no longer requires failure, and that error should no longer occur in browsers;但是对于需要预检情况的跨域请求,其他不允许的请求不再需要失败,并且浏览器中不应再出现该错误; the spec changed in August 2016 to no longer require it , and all browser engines subsequently updated to match that change. 该规范在 2016 年 8 月更改为不再需要它,随后所有浏览器引擎都进行了更新以匹配该更改。

Chrome was the last browser to implement the update, but it was fixed in the Chrome sources in December 2016 , and the fix shipped in Chrome 57. Chrome 是最后一个实施更新的浏览器,但它已于 2016 年 12 月在 Chrome 源中修复,并且该修复在 Chrome 57 中发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 IIS 中的 CORS 问题与 Access-Control-Allow-Origin 中的凭据和通配符 - CORS in IIS issue with credentials and wildcard in Access-Control-Allow-Origin Nodejs Express CORS 问题与“Access-Control-Allow-Origin” - Nodejs Express CORS issue with 'Access-Control-Allow-Origin' CORS 的 Safari 问题:Access-Control-Allow-Origin 不允许来源 - Safari issue with CORS: Origin is not allowed by Access-Control-Allow-Origin IISNOde中的请求资源(AngularJS + NodeJs)上没有“ Access-Control-Allow-Origin”标头 - No 'Access-Control-Allow-Origin' header is present on the requested resource (AngularJS + NodeJs) In IISNOde FirebaseFunctions Cors 没有“访问控制允许来源” - FirebaseFunctions Cors No 'Access-Control-Allow-Origin' CORS,无“访问控制允许来源” - CORS and No 'Access-Control-Allow-Origin' NodeJS - 没有“访问控制允许来源”header - NodeJS - No 'Access-Control-Allow-Origin' header 纯nodejs中的“访问控制允许来源” - 'Access-Control-Allow-Origin' in pure nodejs CORS 问题:我的应用程序中的 npm cors 模块是否正确格式化了“Access-Control-Allow-Origin”字段? - CORS Issue: Is npm cors module formatting "Access-Control-Allow-Origin" field correctly in my application? openshift nodejs应用程序cors 502未指定访问控制允许来源 - openshift nodejs app cors 502 No Access-Control-Allow-Origin specified
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM