浏览器后退按钮上的 CORS 错误

Posted

技术标签:

【中文标题】浏览器后退按钮上的 CORS 错误【英文标题】:CORS Error on browser back button 【发布时间】:2017-05-15 18:38:12 【问题描述】:

我有一个 ASP.NET Web API 2 服务。并且多个客户端(角度)应用程序与该服务对话。应用程序和服务发布在不同的子域上,如下所示:

service.mydomain.com

app1.mydomain.com

app2.mydomain.com

我使用 Microsoft.AspNet.WebApi.Cors - NuGet 包来启用 CORS,它工作正常,除了一种情况: 当用户打开一个应用程序 (app1.mydomain.com) 时。 然后导航到另一个 (app2.mydomain.com)。然后按浏览器后退按钮。以下 CORS 错误:

The 'Access-Control-Allow-Origin' header has a value 'http://app2.mydomain.com' that is not equal to the supplied origin. 
Origin 'http://app1.mydomain.com' is therefore not allowed access

我配置了 Microsoft.AspNet.WebApi.Cors - NuGet 包,如下:

public static void Register(HttpConfiguration config)
        
        var cors = new EnableCorsAttribute(
                //to-do allow cross domains for all maarif.com sites
                origins: "*", //and also tried "http://app1.mydomain.com, http://app2.mydomain.com" gives same result
                headers: "*",
                methods: "*") SupportsCredentials = true;

            config.EnableCors(cors);
        

我在服务器上跟踪了 Origin 标头值。 我将以下代码放在服务“global.asax”中:

protected void Application_BeginRequest()
        
            var origin = HttpContext.Current.Request.Headers["Origin"];

            if (origin != null )
            
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", origin);
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "*");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
            
        

当用户单击“app2.mydomain.com”到“app1.mydomain.com”的返回按钮时会出现问题,请求发送的来源是“app2.mydomain.com”,这就是服务允许访问:HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", 'app2.mydomain.com');

有什么办法吗?

请注意,我不能输入“*”,因为请求已经过身份验证。

【问题讨论】:

【参考方案1】:

问题是由于浏览器的缓存机制造成的。因为当你点击 BACK 按钮时,浏览器会使用缓存中的数据,即使是 AJAX 请求。

为此,浏览器不会重新发送 CORS 预检来检查 Access-Control-Allow-Origin 以获取上一页的来源。然后它会使用最新的Access-Control-Allow-Origin,也就是app2.mydomain.com,这样app1.mydomain.com就会失败。

一个简单的解决方案是在api查询字符串的末尾添加时间戳或随机字符串,例如:

js:

let url = 'https://service.mydomain.com/xxxxx?v=' + Date.now();

但它会忽略 Access-Control-Max-Age,这会在每个对 service.mydomain.com 的请求进行 CORS 预检。

或者您可以在新窗口中强制打开所有指向其他来源的链接,这样就无法执行 BACK 操作。

除了这些,我找不到任何其他解决方案。

更新:

我后来在这个anwser之后进行了测试,然后找到了最终的解决方案:

service.mydomain.com中添加如下HTTP响应头,就OK了。

http:

Cache-Control: no-store,no-cache,must-revalidate
Pragma: no-cache

只需禁用 AJAX 请求的所有缓存即可。 CORS Max-age 也有效。

现在它可以在 Chrome 和 Firefox 中使用。其他浏览器我没试过,但我觉得应该没什么不同。

【讨论】:

我的解决方案是在查询字符串中添加主机(例如?host=app1.domain.com),这样其他域就不会得到缓存的响应。【参考方案2】:

您是否尝试过在您的 StratUp.cs 文件中添加如下内容:

var corsPolicy = new CorsPolicy
            
                AllowAnyMethod = true,
                AllowAnyHeader = true,
                SupportsCredentials = true,
                Origins =  "http://site1.example.com", "http://site2.emaple.com.:38091", "http://localhost:39372" 

            ;

            app.UseCors(new CorsOptions
            
                PolicyProvider = new CorsPolicyProvider
                
                    PolicyResolver = context => Task.FromResult(corsPolicy)
                
            );

在 web.config 中的 webserver 部分可能是这样的:

<system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
    <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>

【讨论】:

其实我正在使用,Web Api 项目使用 'global.asax' 文件而不是 'StratUp.cs' 我试图 HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin" , "app1.mydomain.com, app2.mydomain.com"); 好吧,你喜欢怎么做……但你有没有尝试过我建议你做的事? .. 有用吗? 我这样说:HttpContext.Current.Response.AddHeader("Access-Control-Allow‌​-Origin", "app1.mydomain.com, app2.mydomain.com");但它不起作用,它不接受标头值中的多个域,错误说它必须是单个域 这就是为什么我建议你..尝试我的解决方案......不要把它放在标题中你正在做什么......但尝试用其他方式..然后你在你的网络配置中设置我的答案的 scodn 部分(我现在编辑) 我尝试使用 Microsoft.AspNet.WebApi.Cors Nuget 包,并将其配置为: var cors = new EnableCorsAttribute( //to-do allow cross domain for all maarif.com sites origin: " app1.mydomain.com,app2.mydomain.com",标题:"",方法:"") SupportsCredentials = true; config.EnableCors(cors);它适用于所有场景,除了浏览器从 domain2 到 domain1 它会给出错误

以上是关于浏览器后退按钮上的 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

求HTML网页点击UE浏览器上的后退按钮后能回到上一次浏览的网页的代码!

移动浏览器:后退按钮上的更新元素

重定向到浏览器后退按钮上的特定操作单击 MVC

跟踪用户点击浏览器上的后退按钮的时间

浏览器上的后退按钮是回发?

通过在 L5 中点击浏览器上的后退按钮来防止注销后再次登录?