ASP.net同源策略头不起作用

4

I'm getting the error:

XMLHttpRequest cannot load http://www.scirra.com/handlers/arcadeProcessScore.ashx. Origin http://static1.scirra.net is not allowed by Access-Control-Allow-Origin.

arcadeProcessScore.ashx文件中,我有以下代码行:
public void ProcessRequest (HttpContext context) {

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://static1.scirra.net");
    context.Response.AppendHeader("Access-Control-Allow-Origin", "https://static1.scirra.net");
    context.Response.ContentType = "text/plain";

然而错误仍然存在。

我也试过简单地:

context.Response.AppendHeader("Access-Control-Allow-Origin", "*");

这也不起作用。

如果我在web.config级别添加<add name="Access-Control-Allow-Origin" value="*"/>,它可以工作,但显然不是解决方案。

我该如何让arcadeProcessScore.ashx接受来自static1.scirra.net的请求?感谢任何帮助。

3个回答

5

我自己进行了一些测试,直接使用XmlHttpRequest访问我的项目中的处理程序。我使用的设置是将应用程序发布在我的本地IIS上(版本为6.1,因此可能与7.5的行为有所不同),并且让Default.aspx页面调用在Visual Studio中运行的处理程序。就像这样:

http://mymachine/WebTest/Default.aspx

-> XmlHttpRequest get request to

http://localhost:58025/WebTest/TestHandler.ashx

在处理程序中的代码:

public void ProcessRequest (HttpContext context) {
    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World " + DateTime.Now.ToString());
}

使用IE9,无论我是否从处理程序发送了Access-Control-Allow-Origin头,行为都是相同的。IE9会发出警告,要求用户确认是否应加载内容。
Chrome(版本21.0.1180.79 m)和FF(版本14.0.1)实际上生成请求到处理程序并尊重处理程序发送回来的头信息。
因此,这在Chrome和FF中可以正常工作:
context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");

这就是所发生的事情:
context.Response.AppendHeader("Access-Control-Allow-Origin", "*");

但是我无法让它们两个在同一响应中显示多个不同的允许来源。对我来说,这些都没有起作用:

  1. Add several response headers

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");
    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://someothermachine");
    
  2. Add one header, two origins comma separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine, http://someothermachine");
    
  3. Add one header, two origins space separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine http://someothermachine");
    
  4. Add one header, two origins space separated

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine; http://someothermachine");
    
为了让它工作,我按照这个答案中提供的建议进行操作。我的处理程序看起来像这样:
public void ProcessRequest(HttpContext context)
{
    string[] allowedOrigins = new string[] { "http://mymachine", "http://someothermachine" };
    string origin = context.Request.Headers.Get("Origin");
    if (allowedOrigins.Contains(origin))
        context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World " + DateTime.Now.ToString());
}

通过这样做,Chrome和FF都能接受来自两个来源的处理程序输出。


1
这是我解决问题的一部分。即使我使用的代码非常类似于此处列出的代码,Chrome仍然会抛出起源问题。我的问题发生在我既设置了Access-Control-Allow-Origin标头的代码,又在我的Web配置中添加了<add name="Access-Control-Allow-Origin" value="*" />这一行。一旦我从我的Web配置中删除了这一行,我就可以运行了。 - Garry

3
您的代码问题在于,跨源响应标头与实际请求一起发送到浏览器中,而它必须在实际请求之前存在! W3建议 用户代理在提交实际跨源HTTP请求之前实现预检请求,这意味着包含实际请求的页面的响应或称为预检请求(在实际请求之前进行)的响应在实际请求时必须包含跨源响应标头。
预检请求返回的跨源标头存储在预检结果缓存中。当发出跨源HTTP请求时,用户代理会检查预检结果缓存中的Access-Control-Allow-Origin标头,如果不存在,则抛出异常,显示:
无法加载地址,源地址未被Access-Control-Allow-Origin允许。当你在web.config中添加Access-Control-Allow-Origin头时,任何从服务器返回的响应都包含Access-Control-Allow-Origin头,浏览器将会提交实际的跨域请求。最好的方法是在调用实际的跨域请求之前,进行简单的ajax调用(预检请求),并发送所需的任何响应头。

1
你能否将你的web.config项目包装在一个location标签中,以便它仅在ashx位置运行,而不是其他任何地方 - 这样是否可以缓解“显然不是答案”的问题?
<location path="~/path/to/handler/arcadeProcessScore.ashx">
<httpProtocol>
   <customHeaders>
      <clear />
      <add name="Access-Control-Allow-Origin" value="http://static1.scirra.net" />
   </customHeaders>
</httpProtocol>
</location>

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