【问题标题】:Access-Control-Allow-Origin - localhost访问控制允许来源 - 本地主机
【发布时间】:2012-12-15 15:12:21
【问题描述】:

我在通过 ajax 接收 json 时遇到问题,错误如下。根据我迄今为止发现的有关该错误的信息,这似乎是某种跨域问题,但我不知道这意味着什么以及如何解决它。

响应头可能有问题(我自己创建了 API,之前没有经验),但是如果直接在浏览器中访问 url,则会收到 200 OK。

如果直接在浏览器中访问 url 会显示有效的 json,那么这应该不是问题。

如何解决?

注意:该 url 转到 Apache 服务器,而不是我在 Stack 上阅读过的有关该问题的 95% 问题的文件。

检查器出错:

XMLHttpRequest cannot load http://localhost/api/v1/products?_=1355583847077.
Origin null is not allowed by Access-Control-Allow-Origin.
Error: error 

代码:

    $.ajaxSetup ({
      url: "http://localhost/api/v1/products", // <--- returns valid json if accessed in the browser
      type: "GET",
      dataType: "json",
      cache: false,
      contentType: "application/json"
    })
    $.ajax({
        success: function(data){

            console.log("You made it!");
        },
        error: function(xhr) {
           console.log("Error: " + xhr.statusText);
       }
    }).done(function(data){
        console.log(data);
    })

参数

_1355583610778

标题

响应标头:

Connection  Keep-Alive
Content-Length  3887
Content-Type    application/json
Date    Sat, 15 Dec 2012 14:50:53 GMT
Keep-Alive  timeout=5, max=100
Server  Apache/2.2.14 (Unix) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l PHP/5.3.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By    PHP/5.3.1

请求标头:

Accept  application/json, text/javascript, */*; q=0.01
Accept-Encoding gzip, deflate
Accept-Language sv-SE,sv;q=0.8,en-US;q=0.5,en;q=0.3
Connection  keep-alive
Host    localhost
Origin  null
User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:17.0) Gecko/17.0 Firefox/17.0

响应

这里什么都没有……

【问题讨论】:

  • 您是否尝试从不同的协议(例如 https 、不同的端口或子域)访问?
  • holyredbeard,关于 URL 转到 Apache 服务器而不是文件的观点,我想知道您是否不知道“绝对”和“相对” URL 之间的区别。经过一些背景阅读后,我想您会发现您认为的“文件”请求实际上是对服务于当前页面的同一台服务器的请求。我猜没有“http://...”会让你感到困惑。
  • @Beetroot-Beetroot:好的,所以如果我在服务器上实时发布 API,这个问题可能会消失,如果我没听错的话?
  • 您当然应该尝试从为原始页面提供服务的同一台服务器上提供api/v1/products - 这是大多数网站采用的传统单域单服务器模型。我不能肯定这是否会解决问题,但它肯定会消除作为错误来源的跨域问题。
  • 服务器当然可以在本地主机上...但必须与您发送 AJAX 请求的页面相同

标签: jquery ajax json api http-headers


【解决方案1】:

是的,这绝对是一个跨域问题。不过别担心,这个问题有两种解决方案。

使用 JSONP

您可以在服务器(即Fergus Morrow's solution)上实现对 JSONP(带填充的 JSON)的支持。 JSONP 开箱即用的跨域工作,基本上是用函数调用填充 JSON。

在您的.ajaxSetup 中将dataType 设置为jsonp,然后在服务器端,您应该确保在请求中检查名为callback 的url 参数。如果设置了该参数,则必须相应地填充 JSON 响应。

parseThis({ "json": "can", "be": "put", "in": "here" });

以上假设callback 设置为parseThis。默认情况下,jQuery 会生成一个函数名称,但您可以通过在 .ajaxSetup 中设置 jsonpCallback 的值来覆盖它。

您还可以使用快捷方式告诉 jQuery 您正在请求 JSONP,只需将 ?callback=? 添加到请求 url。

使用 Access-Control-Allow-Origin

另一种解决方案是在您的响应中设置 Access-Control-Allow-Origin 标头。

Access-Control-Allow-Origin: *

以上将允许任何资源跨域使用服务。阅读下面链接的文章,了解有关如何配置 Access-Control-Allow 的更多信息。


如果您想了解有关 Access-Control-Origin 和 CORS 的更多信息,我推荐 this article on MDN。

【讨论】:

  • 请不要在未评论原因的情况下投反对票。如果我不知道有什么问题,我不知道如何改进我的答案:(
  • 我加了一个 +1,因为您还在帖子中解释了 Access-Control-Allow-Origin 标题;我上次看的时候你有+2! ://
  • @FergusMorrow 出于某种原因投赞成票的同一个人改了改投反对票。可能是一个错误,但我想知道。感谢您的支持;)
【解决方案2】:

我通过在我的服务器代码 (php) 中添加以下标头以非常简单的方式解决了这个问题:

header('Access-Control-Allow-Origin: *');

【讨论】:

  • 我喜欢在 SO 上找到的那种答案。
  • 不要使用 *.它允许每个人访问脚本。而是使用您要允许的实际域
【解决方案3】:

尝试并实现某种形式的JSONP 机制。如果您使用的是 PHP,它可能就像这样简单......

/* If a callback has been supplied then prepare to parse the callback
 ** function call back to browser along with JSON. */
$jsonp = false;
if ( isset( $_GET[ 'callback' ] ) ) {
    $_GET[ 'callback' ] = strip_tags( $_GET[ 'callback' ] );
    $jsonp              = true;

    $pre  = $_GET[ 'callback' ] . '(';
    $post = ');';
} //isset( $_GET[ 'callback' ] )

/* Encode JSON, and if jsonp is true, then ouput with the callback
 ** function; if not - just output JSON. */
$json = json_encode( /* data here */ );
print( ( $jsonp ) ? $pre . $json . $post : $json );

所有这一切都会检查一个名为 callback 的 $_GET var,然后将输出包装在一个函数调用中 - 将 $_GET['callback'] 名称作为函数名称。

那么你的 AJAX 调用就变成了这样……

$.ajax({
  type: 'GET',
  url: '/* script here */ ', 
  data: /* data here - if any */,
  contentType: "jsonp", // Pay attention to the dataType/contentType
  dataType: 'jsonp', // Pay attention to the dataType/contentType
  success: function (json) {
    /* call back */
  }
});

当 jQuery 被指定为 'jsonp' 作为 dataType/contentType 时,它​​将负责为您提供回调函数名称 - 并设置回调函数等;这意味着您实际上不必做任何事情!

来自 jQuery 文档:

“jsonp”:使用 JSONP 加载到 JSON 块中。添加一个额外的“?callback =?”到 URL 的末尾以指定回调。通过将查询字符串参数“_=[TIMESTAMP]”附加到 URL 来禁用缓存,除非缓存选项设置为 true。

Source

结束; JSONP 将是你最好的选择——我在你的服务器端脚本使用 PHP 的情况下包含了 PHP 代码;如果不是,那么原则是相同的。不管服务器端技术如何,jQuery/客户端的东西都保持不变。 (一般)

祝你好运:)

【讨论】:

  • 非常感谢这个描述性的答案。我已经实施了解决方案,但它仍然是错误的。 :/ 这是 errorThrown 在浏览器中告诉我的:“错误:未调用 jQuery18308595284975599498_1355591723832”
  • 这表明服务器没有返回 JSONP,但仍返回纯 JSON。 :/ 你是如何在服务器端实现 JSONP 解决方案的?如果可能,请在浏览器中打开 http://localhost/api/v1/products 文件并查看它返回的内容,然后在 URL 中添加一个 ?callback=test,并查看输出是否正确包装在对 test( ) 的调用中。我希望这是有道理的!
  • 我已经实现了您在回答中提供的解决方案,并且我已经检查了如果提供对 url 的回调,则 if 语句为真。但是,当我在浏览器中手动打开 url 时,包括 ?callback=test 输出与没有 ?callback=test 的输出完全相同。奇怪...
  • 您是否在 sn-p 的最后一行添加了类似于三元语句的内容?负责发送打包输出的那一行 - if 块本身只是准备它!
【解决方案4】:

如果它是一个 ASP.NET WEB 应用程序,那么你也可以把它放在你的 Global.aspx 中:

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

【讨论】:

    【解决方案5】:

    更多 PHP 标头设置

    header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
    header('Access-Control-Max-Age: 1000');
    header('Access-Control-Allow-Headers: Content-Type');
    

    祝你好运

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      • 2017-12-15
      • 2016-08-18
      相关资源
      最近更新 更多