起源不被Access-Control-Allow-Origin允许。

369
我正在一个Sencha Touch 2应用程序(封装在PhoneGap中)中向远程PHP服务器发出Ajax.request请求。
来自服务器的响应如下:

XMLHttpRequest无法加载http://nqatalog.negroesquisso.pt/login.php。由于Access-Control-Allow-Origin未允许,源http://localhost:8888不被允许。

我该如何解决这个问题?

20
在使用jQuery时,设置dataType: 'jsonp'可以解决问题。 - Amit Kosti
11
顺便提一下,那不是服务器的响应。更确切地说,该错误是在客户端发生的。 - matteo
2
jsonp技巧可能已经不再起作用了,FYI:https://dev59.com/questions/SGct5IYBdhLWcg3wQ7bP - drewww
8
请注意,由于我刚刚浪费了半天时间追踪这个 bug - 如果服务器端脚本出现内部服务器错误,浏览器可能会将其解释为请求被拒绝,原因是缺少 Access-Control-Allow-Origin,并将其报告为错误。 - troelskn
1
有一个扩展程序可以解决这个问题! - cregox
18个回答

388

我之前写了一篇关于这个问题的文章,跨域 AJAX

如果你可以控制响应服务器,处理这个问题最简单的方法是添加一个响应头:

Access-Control-Allow-Origin: *

这将允许跨域Ajax。在PHP中,您需要修改响应如下:

<?php header('Access-Control-Allow-Origin: *'); ?>

你可以将Header set Access-Control-Allow-Origin *设置放在Apache配置文件或htaccess文件中。

需要注意的是,这实际上禁用了CORS保护,这很可能会暴露你的用户受到攻击。如果你不知道你是否需要使用通配符,那么就不要使用它,而应该将你的特定域名添加到白名单中:

<?php header('Access-Control-Allow-Origin: http://example.com') ?>

5
我会联系我的服务器提供商。谢谢。 - Ricardo
9
这样有安全隐患吗?例如,这个回答说:“由于安全原因,JavaScript 受到“同源策略”的限制。例如,一个恶意脚本无法联系远程服务器并从您的网站发送敏感数据。” - JohnK
4
太棒了,我刚把这行代码放入我的node.js服务器文件:response.writeHead(200, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': '*' });然后它就生效了。谢谢! - vbullinger
26
JohnK,是的,通配符允许任何域向您的主机发送请求。我建议将星号替换为您将在其上运行脚本的特定域名。 - Nick
7
有趣的是,你认为 @jfrej 不应该建议使用通配符。这取决于你的目标。例如,我们使用通配符(并发布了这个答案)的原因是因为我们正在为任何网站构建嵌入式小部件。 - Matt Mombrea
显示剩余3条评论

64

如果你没有服务器控制权,你可以在Chrome启动器中添加此参数:--disable-web-security

但请注意,我不建议在正常的"网页浏览"时使用这个参数。具体信息可参考此帖: 在Chrome中禁用同源策略

一旦你使用Phonegap构建应用并将其加载到设备上,这将不再是问题。


5
你可以简单地将这个参数添加到你的Chrome启动器中。在Chrome内部没有此设置。 - Travis Webb
这不是一个好的建议 - 它只会掩盖问题,使其在您自己的开发机器上工作。采用这种方法意味着您的应用程序将在生产环境中出现故障,因为您的用户将没有禁用安全性。请按照上面接受的答案来正确解决此问题。 - providencemac
3
当然是不安全的。发帖者正在寻找绕过安全措施的方法。 - Travis Webb
它以前能够工作,但我猜在Chrome 49中不行了! - omid.n
更新:您需要做的是一起使用 --user-data-dir 和 --disable-web-security 标志(Chrome 49+)。 - omid.n
显示剩余5条评论

42
如果您正在使用Apache,只需添加以下内容:
<ifModule mod_headers.c>
    Header set Access-Control-Allow-Origin: *
</ifModule>

您可以在配置中添加 *,这将会导致您的web服务器所有响应可以从互联网上的任何其他站点访问。如果您希望只允许特定服务器使用您主机上的服务,可以将 * 替换为原始服务器的URL:

Header set Access-Control-Allow-Origin: http://my.origin.host

3
别忘了加载模块:a2enmod headers。 - Walery Strauch
如何加载模块:a2enmod headers? - Ayesha

18

如果您有一个ASP.NET / ASP.NET MVC应用程序,您可以通过Web.config文件添加此标题:

<system.webServer>
  ...

    <httpProtocol>
        <customHeaders>
            <!-- Enable Cross Domain AJAX calls -->
            <remove name="Access-Control-Allow-Origin" />
            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

2
.NET MVC的朋友们,看这里!我实际上要打出一个解决方案,并在我的博客上指向这个答案,以便人们可以更容易地找到它。最糟糕的是试图克服.NET/MVC障碍,却找不到除了PHP/jQuery解决方案之外的任何东西。谢谢@Caio-Proiete。 - ottoflux
1
为什么这对我不起作用?我正在使用Chrome,尝试从我的本地主机访问雅虎财经页面。 - newman
1
谢谢,它对我有用。我已经将其添加到服务器端代码项目(web.config)中。 - ethem

15
这是我在尝试使用ASP.NET MVC作为数据源解决相同问题时遇到的第一个问题/答案。我意识到这并不能解决PHP的问题,但它与之有足够相关性。
我正在使用ASP.NET MVC。Greg Brant的博客文章对我很有用。最终,您将创建一个属性[HttpHeaderAttribute("Access-Control-Allow-Origin", "*")],您可以将其添加到控制器操作中。
例如:
public class HttpHeaderAttribute : ActionFilterAttribute
{
    public string Name { get; set; }
    public string Value { get; set; }
    public HttpHeaderAttribute(string name, string value)
    {
        Name = name;
        Value = value;
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.AppendHeader(Name, Value);
        base.OnResultExecuted(filterContext);
    }
}

然后使用它:

[HttpHeaderAttribute("Access-Control-Allow-Origin", "*")]
public ActionResult MyVeryAvailableAction(string id)
{
    return Json( "Some public result" );
}

1
WebApi 2 现在已内建此功能。http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api - Matt Frear

10

正如Matt Mombrea所说的那样,对于服务器端,您可能会遇到另一个问题,即白名单拒绝访问。

您需要配置您的phonegap.plist文件。(我正在使用旧版本的phonegap)

对于cordova,命名和目录可能有所变化。但步骤应该大致相同。

首先选择Supporting files > PhoneGap.plist

输入图像描述

然后在“ExternalHosts”下面

添加一个条目,值为"http://nqatalog.negroesquisso.pt" 我正在使用*仅用于调试目的。

输入图像描述


8

对于需要针对引用方的“www”和“non-www”版本都进行异常处理的任何人来说,这可能会很有用:

 $referrer = $_SERVER['HTTP_REFERER'];
 $parts = parse_url($referrer);
 $domain = $parts['host'];

 if($domain == 'google.com')
 {
         header('Access-Control-Allow-Origin: http://google.com');
 }
 else if($domain == 'www.google.com')
 {
         header('Access-Control-Allow-Origin: http://www.google.com');
 }

指导我解决了在Azure中出现的ACAO错误。虽然我已经添加了允许的主机名googledrive,但需要使用的URL是https://googledrive/而不是https://www.googledrive/。 - Kildareflare

7
我将为您提供一个简单的解决方案。在我的情况下,我无法访问服务器。在这种情况下,您可以更改Google Chrome浏览器中的安全策略,以允许Access-Control-Allow-Origin。这非常简单:
  1. 创建Chrome浏览器快捷方式
  2. 右键单击快捷方式图标 -> 属性 -> 快捷方式 -> 目标

只需在其中粘贴 "C:\Program Files\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files --disable-web-security

位置可能不同。现在通过单击该快捷方式打开Chrome。


7

在使用各种API时,我遇到了这个问题几次。通常,一个快速的解决方法是在字符串的末尾添加"&callback=?"。有时候,&符号需要用字符编码代替,有时候则是"?":"?callback=?" (参见Forecast.io API Usage with jQuery)


7
这是因为同源策略。请查看Mozilla Developer NetworkWikipedia以获取更多信息。
基本上,在您的示例中,您需要仅从nqatalog.negroesquisso.pt而不是localhost加载http://nqatalog.negroesquisso.pt/login.php页面。

1
但是我需要从移动设备加载Web服务,我能绕过这个吗? - Ricardo
你需要进行一些服务器端的更改或使用JSONP。http://en.wikipedia.org/wiki/JSONP - antyrat

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