jQuery AJAX跨域


477

这是两个页面,test.php和testserver.php。

test.php

<script src="scripts/jq.js" type="text/javascript"></script>
<script>
    $(function() {
        $.ajax({url:"testserver.php",
            success:function() {
                alert("Success");
            },
            error:function() {
                alert("Error");
            },
            dataType:"json",
            type:"get"
        }
    )})
</script>

testserver.php

<?php
$arr = array("element1",
             "element2",
             array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>

现在我的问题是:当这两个文件都在同一服务器上(本地主机或Web服务器)时,它可以工作并被alert("Success")调用;如果它在不同的服务器上,则意味着Web服务器上的testserver.php和localhost上的test.php,它不起作用,并且alert("Error")正在执行。即使ajax内的URL更改为http://domain.com/path/to/file/testserver.php


38
对于路过的人。阅读
此书可

1
我在这里写了这个问题的答案:使用jQuery AJAX加载跨域html页面最后一个,支持https
jherax 2014年

Answers:


412

使用JSONP

jQuery的:

$.ajax({
     url:"testserver.php",
     dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
     success:function(json){
         // do stuff with json (in this case an array)
         alert("Success");
     },
     error:function(){
         alert("Error");
     }      
});

PHP:

<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>

回声可能是错误的,因为我使用过php已经有一段时间了。无论如何,您都需要输出callbackName('jsonString')引号。jQuery将传递它自己的回调名称,因此您需要从GET参数中获取该名称。

正如Stefan Kendall 所说的那样,$ .getJSON()是一种简写方法,但是您需要将'callback=?'它作为GET参数附加到url(是,值是?,jQuery用它自己生成的回调方法替换了它)。


2
为什么您需要返回callbackName('/* json */')而不是callbackName(/* json */)
艾瑞克(Eric)

3
@eric回调需要JSON字符串。从理论上讲,一个对象也可以正常工作,但是不确定jQuery如何对此做出响应,它可能会引发错误或无提示地失败。
BGerrissen 2011年

我收到以下错误。语法错误:丢失;在语句{“ ResultCode”:2}之前。其中{“ ResultCode”:2}是响应。请指教。
user2003356 2014年

@ user2003356看起来您正在返回纯JSON而不是JSONP。您需要返回以下内容:callbackFunction({“ ResultCode”:2})。jQuery将GET参数“ callback”添加到请求中,这是jquery使用的回调函数的名称,应将其添加到响应中。
BGerrissen 2014年

2
现在是2016年。现在,CORS是一个得到广泛支持的标准,与JSONP(只能描述为黑客)相对。现在,@ joshuarh的答案应该是首选。
Vicky Chijwani'7

202

JSONP是一个不错的选择,但是有一种更简单的方法。您只需Access-Control-Allow-Origin在服务器上设置标题即可。将其设置为*将接受来自任何域的跨域AJAX请求。(https://developer.mozilla.org/en/http_access_control

当然,这种方法会因语言而异。在Rails中:

class HelloController < ApplicationController
  def say_hello
    headers['Access-Control-Allow-Origin'] = "*"
    render text: "hello!"
  end
end

在此示例中,该say_hello操作将接受来自任何域的AJAX请求并返回“ hello!”响应。

这是可能返回的标头的示例:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive

它很简单,但是确实有一些浏览器限制。请参阅http://caniuse.com/#feat=cors


12
Jsonp不支持发布,放置和删除。您的解决方案效果很好。
TonyTakeshi

35
在PHP标头中(“ Access-Control-Allow-Origin:*”);
SparK 2012年

9
@Warrior如果使用的是jQuery .post()方法,则必须在jQuery中启用跨域支持。为此:$.support.cors = true
Friederike 2013年

21
以这种方式配置服务器有哪些安全隐患?
乔恩·施耐德

19
最好只允许与您共享数据的那些域,而不要使用通配符“ *”。
塞巴斯蒂安·格里尼亚利

32

您可以通过添加Access-Control-Allow-Origin通过HTTP标头来控制它。将其设置为*将接受来自任何域的跨域AJAX请求。

使用PHP非常简单,只需将以下行添加到要从您的域外部访问的脚本中:

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

不要忘记在httpd.conf中启用mod_headers模块。


你救了我的一天。
NomanJaved

20

您需要看一下同源起源政策

在计算中,对于许多浏览器端编程语言(例如JavaScript),相同的源策略是重要的安全概念。该策略允许运行在源自同一站点的页面上的脚本不受特定限制地访问彼此的方法和属性,但可以阻止跨不同站点的页面访问大多数方法和属性。

为了使您能够获取数据,它必须是:

相同的协议和主机

您需要实现JSONP来解决它。


17

我必须从本地磁盘“ file:/// C:/test/htmlpage.html”加载网页,调用“ http://localhost/getxml.php” URL,并在IE8 +和Firefox12 +浏览器中执行此操作,使用jQuery v1 .7.2 lib以最小化样板代码。阅读了数十篇文章后,终于弄明白了。这是我的总结。

  • 服务器脚本(.php,.jsp等)必须返回http响应标头Access-Control-Allow-Origin:*
  • 在使用jQuery ajax之前,请在javascript中设置此标志:jQuery.support.cors = true;
  • 您可以在使用jQuery ajax函数之前一次或每次设置标志
  • 现在,我可以在IE和Firefox中阅读.xml文档。我未测试的其他浏览器。
  • 响应文档可以是纯文本/文本,xml,json或其他任何内容

这是一个带有一些调试sysouts的示例jQuery ajax调用。

jQuery.support.cors = true;
$.ajax({
    url: "http://localhost/getxml.php",
    data: { "id":"doc1", "rows":"100" },
    type: "GET",
    timeout: 30000,
    dataType: "text", // "xml", "json"
    success: function(data) {
        // show text reply as-is (debug)
        alert(data);

        // show xml field values (debug)
        //alert( $(data).find("title").text() );

        // loop JSON array (debug)
        //var str="";
        //$.each(data.items, function(i,item) {
        //  str += item.title + "\n";
        //});
        //alert(str);
    },
    error: function(jqXHR, textStatus, ex) {
        alert(textStatus + "," + ex + "," + jqXHR.responseText);
    }
});

1
我在这里为这个问题写了一个答案:使用jQuery AJAX加载跨域html页面最后一个,支持https
jherax 2014年

最重要的一点:在PHP中将此行添加到脚本中:header("Access-Control-Allow-Origin: *");
T30

1
@whome非常感谢您的回答。你帮了我很多忙 干杯。
路易斯·米兰尼斯

10

确实,同源策略可以阻止JavaScript跨域发出请求,但是CORS规范仅允许您要查找的API访问类型,并且当前一批主要浏览器都支持。

了解如何为客户端和服务器启用跨域资源共享:

http://enable-cors.org/

“跨源资源共享(CORS)是一种允许跨域边界真正开放访问的规范。如果您提供公共内容,请考虑使用CORS对其进行开放以实现通用JavaScript /浏览器访问。”



9

我使用Apache服务器,所以我使用过mod_proxy模块。启用模块:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

然后加:

ProxyPass /your-proxy-url/ http://service-url:serviceport/

最后,将proxy-url传递给脚本。




4

从Jquery docs(link):

  • 由于浏览器安全性的限制,大多数“ Ajax”请求都受相同的原始策略限制;该请求无法成功从其他域,子域或协议检索数据。

  • 脚本和JSONP请求不受相同的原始策略限制。

因此,我认为您需要对请求使用jsonp。但是我自己还没有尝试过。


2

我知道3种解决您的问题的方法:

  1. 首先,如果您有权访问两个域,则可以使用以下命令允许对所有其他域的访问:

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

    或仅将域名添加到.htaccess文件中:

    <FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>

  2. 您可以向服务器中的php文件提出ajax请求,并使用此php文件处理对另一个域的请求。

  3. 您可以使用jsonp,因为它不需要许可。为此,您可以阅读我们的朋友@BGerrissen的答案。


0

它有效,您需要的全部:

PHP:

header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

JS(jQuery ajax):

var getWBody = $.ajax({ cache: false,
        url: URL,
        dataType : 'json',
        type: 'GET',
        xhrFields: { withCredentials: true }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.