4

我收到错误:

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", "*");

这也不起作用。

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

我怎样才能让arcadeProcessScore.ashx接受来自的请求static1.scirra.net?谢谢你的帮助。

4

3 回答 3

5

我自己做了一些测试,直接使用 anXmlHttpRequest来访问我项目中的处理程序。我使用的设置是在我的本地 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. 添加几个响应头

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine");
    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://someothermachine");
    
  2. 添加一个标题,两个来源逗号分隔

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine, http://someothermachine");
    
  3. 添加一个标题,两个来源空间分隔

    context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine http://someothermachine");
    
  4. 添加一个标题,两个来源空间分隔

    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 都接受来自两个来源的处理程序的输出。

于 2012-08-17T10:24:39.607 回答
3

您的代码的问题是跨源响应标头实际请求一起发送到浏览器,而在发出实际请求之前它必须存在!

W3 建议用户代理在提交实际的跨域 HTTP 请求之前实现预检请求,这意味着要么对包含实际请求的页面的响应,要么对称为预检请求的简单请求的响应(在实际请求)在发出实际请求时必须包含跨域响应标头。

预检请求返回的跨域标头存储在预检结果缓存中。当发出跨域 HTTP 请求时,用户代理会检查预检结果缓存Access-Control-Allow-Origin中的标头,如果不存在则抛出异常说明:

无法加载地址,Access-Control-Allow-Origin 不允许原始地址。

当你将Access-Control-Allow-Originheader 放入 中时web.config,服务器返回的任何响应都包含Access-Control-Allow-Originheader,浏览器提交实际的跨域请求。

您最好的选择是在调用实际的跨域请求之前进行简单的 ajax 调用(预检请求),并发送该预检请求所需的任何响应标头。

于 2012-08-17T10:29:34.843 回答
1

您能否将您的 web.config 项目包装在一个位置标签中,以便它只在您的 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>
于 2012-08-17T08:17:41.273 回答