首页 > 代码库 > ajax跨域问题-----jsonp

ajax跨域问题-----jsonp

1.浏览器的同源策略:域名,协议,端口均相同,叫做同源

举个例子:

http://www.123.com/index.html 调用 http://www.123.com/server.PHP (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

 

2.跨域:浏览器不能执行其他网站的脚本

3.解决跨域的方法:

(1)JSONP

 

JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

  将JSON数据填充进回调函数

举个例子:

www.test1.com域名A下有一个文件A:a.html

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
   <meta charset="utf-8">
    <meta name="keywords" content="">
    <meta name="description" content="">
    <meta name="author" content="author">
    <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-title" content="">
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
    <meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=http://www.mamicode.com/myAffiliateData, app-argument=myURL">
    <meta name="format-detection" content="telphone=no, email=no"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <!--remove weixin‘s cache -->
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <title>a.html</title>

   <script type="text/javascript" src="http://test2.com/test.js"></script> 
</head>
<body>

</body>
</html>

 

www.test2.com域名B下有一个文件B,test.js:

alert("success")

 

域名A想访问域名B,

<script type="text/javascript" src="http://test2.com/test.js"></script> 
若如上调用,则可以访问到
若如下调用,则不可访问到,因为浏览器跨域了。

<script type="text/javascript" src="http://www.mamicode.com/test.js"></script> 

--那如何通过jsonp来访问到test.js呢?

----jsonp简单小例子:

a.html:

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
   <meta charset="utf-8">
    <title></title>
    
  <script type="text/javascript">
//创建一个回调函数
       function callback(data) {
    alert(data.message);
}
   </script>
   <script type="text/javascript" src="http://test2.com/test.js"></script> 
</head>
<body>

</body>
</html>

test.js:

//调用callback函数,并以json数据形式作为阐述传递,完成回调
callback({message:"success"}); 

好了,完成一个jsonp的小例子,这样做,域名A就可以访问域名B中的test.js了。但是这样的话,test.js是在html还没加载完就已经弹出信息了,很不方便。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务

----动态创建script标签,实现jsonp

a.html:

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
   <meta charset="utf-8">
    <title></title>
    
  <script type="text/javascript">
//添加<script>标签的方法
    function addScriptTag(src){
        var script = document.createElement(script);
        script.setAttribute("type","text/javascript");
        script.src = src;
        document.body.appendChild(script);
    }
    
    window.onload = function(){
        //搜索apple,将自定义的回调函数名result传入callback参数中
        //为了方便演示:假设test.js为http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=result
      //此链接是服务端已经设置好jsonp的获取文件
addScriptTag("http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=result"); } //自定义的回调函数result function result(data) { //我们就简单的获取apple搜索结果的第一条记录中url数据 alert(data.postalcodes[0].adminCode2); } </script> </head> <body> </body> </html>
http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=回调函数名
callback=回调函数名,就是你在a.html文件里写的自定义回调函数result

此处再强调一遍jsonp:

JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

  将JSON数据填充进回调函数

jQuery对jsonp的实现(转)

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法(详细可以参考http://api.jquery.com/jQuery.getJSON/)。那我们就来修改下程序A的代码,改用jQuery的getJSON方法来实现(下面的例子没用用到向服务传参,所以只写了getJSON(url,[callback])):

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$.getJSON("http://localhost:20002/MyService.ashx?callback=?",function(data){
alert(data.name + " is a a" + data.sex);
});
</script>

  结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个问号是内部自动生成的一个回调函数名。这个函数名大家可以debug一下看看,比如jQuery17207481773362960666_1332575486681。

  当然,加入说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现(参数较多,详细可以参考http://api.jquery.com/jQuery.ajax)。先来看看如何实现吧:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$.ajax({
url:"http://localhost:20002/MyService.ashx?callback=?",
dataType:"jsonp",
jsonpCallback:"person",
success:function(data){
alert(data.name + " is a a" + data.sex);
}
});
</script>

  没错,jsonpCallback就是可以指定我们自己的回调方法名person,远程服务接受callback参数的值就不再是自动生成的回调名,而是person。dataType是指定按照JSOPN方式访问远程服务。

(2)跨域解决方法2----代理:

例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。

 

(3)跨域解决方法3----PHP端修改header(XHR2方式)

在php接口脚本中加入以下两句即可:

header(‘Access-Control-Allow-Origin:*‘);//允许所有来源访问

header(‘Access-Control-Allow-Method:POST,GET‘);//允许访问的方式

ajax跨域问题-----jsonp