我收到错误:
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
的请求? 感谢您的任何帮助。
我自己做了一些测试,直接使用 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", "*");
但是,如果我尝试在同一响应中添加几个不同的允许来源,我将无法让它们中的任何一个显示内容。对我来说,这些都不起作用:
添加多个响应标头
context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine"); context.Response.AppendHeader("Access-Control-Allow-Origin", "http://someothermachine");
添加一个标题,两个原点逗号分隔
context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine, http://someothermachine");
添加一个标题,两个原点空格分隔
context.Response.AppendHeader("Access-Control-Allow-Origin", "http://mymachine http://someothermachine");
添加一个标题,两个原点空格分隔
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 都接受来自两个源的处理程序的输出。
代码的问题在于,跨源响应标头与实际请求一起发送到浏览器,而它必须在发出实际请求之前就存在!
W3 建议用户代理在提交实际的跨源 HTTP 请求之前实现预检请求,这意味着对包含实际请求的页面的响应,或对称为预检请求的简单请求的响应(在实际请求之前发出)必须在发出实际请求时包含跨源响应标头。
从预检请求返回的跨源标头存储在印前检查结果缓存中。发出跨源 HTTP 请求时,用户代理会检查预检结果缓存中的 Access-Control-Allow-Origin
标头,如果不存在,则会引发异常,指出:
无法加载地址,访问控制允许源不允许源地址。
当您将 Access-Control-Allow-Origin
标头放入web.config
中时,服务器返回的任何响应都包含 Access-Control-Allow-Origin
标头,浏览器将提交实际的跨域请求。
最好的办法是在调用实际的跨域请求之前进行简单的 ajax 调用(预检请求),并发送该预检请求所需的任何响应标头。
您能否将 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>