jsonp跨域请求,常见的集中书写方式,及优缺点比较

时间:2022-08-28 16:06:11
简介

    符合Web2.0特征的众多网站一个明显的特点就是采用Ajax。Ajax提供了在后台提交请求访问数据的功能。其实现主要使用的是XMLHttpRequest函数,这个函数允许客户端的Javascript发送到服务器端的HTTP请求并获得返回数据。Ajax同时也是目前众多的Mashup背后的驱动力量,他们都利用Ajax来聚合不同来源的信息。


理解同源策略的限制
         同源策略是指阻止代码获得或者更改从另一个域名下获得的文件或者信息。也就是说我们的请求地址必须和当前网站的地指相同。同源策略通过隔离来实现对资源的保护。这个策略的历史非常悠久从Netscape Navigator 2.0时代就开始了。

         

         所谓同源是指,域名,协议,端口均相同,不明白没关系,举个例子:        

           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虽然都指向本机,但也属于跨域。

           浏览器执行JavaScript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

解决方法:

  1.jsonp

     优点:1.1它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
                1.2它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
                1.3在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分开了。我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个jsonp服务。

     缺点:2.1它只支持GET请求而不支持POST等其它类型的HTTP请求
                2.2它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
                2.3 jsonp在调用失败的时候不会返回各种HTTP状态码。
                2.4缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。

    示例代码:

       后台代码(php):http://localhost/json.php    

    <?php
header("Content-type:text/json");
$json2='{"success":true,"array":[{"top1_id":11,"top1":"思想品德修养","top2_id":2,"top2":"公民素养"},{"top1_id":11,"top1":"思想品德修养","top2_id":3,"top2":"理想信念"},{"top1_id":11,"top1":"思想品德修养","top2_id":4,"top2":"人格品质"},{"top1_id":11,"top1":"思想品德修养","top2_id":5,"top2":"行为习惯"},{"top1_id":11,"top1":"思想品德修养","top2_id":6,"top2":"其他"},{"top1_id":11,"top1":"思想品德修养","top2_id":34,"top2":"的斯蒂芬斯蒂芬"},{"top1_id":11,"top1":"思想品德修养","top2_id":35,"top2":"法规的法规的法规的法规"},{"top1_id":11,"top1":"思想品德修养","top2_id":38,"top2":"斯蒂芬斯蒂芬斯蒂芬"},{"top1_id":11,"top1":"思想品德修养","top2_id":40,"top2":"胜多负少的"},{"top1_id":11,"top1":"思想品德修养","top2_id":41,"top2":"阿萨德地方"},{"top1_id":11,"top1":"思想品德修养","top2_id":46,"top2":"LOL"},{"top1_id":11,"top1":"思想品德修养","top2_id":50,"top2":"141414"},{"top1_id":17,"top1":"一级指标","top2_id":59,"top2":"tyutyu"},{"top1_id":17,"top1":"一级指标","top2_id":70,"top2":"zzzzzzzzzzz"},{"top1_id":12,"top1":"智力发展","top2_id":71,"top2":"121212"},{"top1_id":12,"top1":"智力发展","top2_id":72,"top2":"1212121212"}]}';
echo $_GET["call"].'('.$json2.')';
?>

     前台页面(普通html页面):

       方法1:直接请求文件地址,从回调函数获取数据

           <script type="text/javascript">
function callBackOne(data){
console.log(data);
}
</script>
<script src="http://localhost/json.php?call=callBackOne" type="text/javascript"></script>
      方法2:  动态拼接script标签进行请求

          <script type="text/javascript">
function callBackTwo(data){
console.log(data);
}
var urlSrc = 'http://localhost/json.php?call=callBackTwo';
var script = document.createElement('script');
script.setAttribute('src',urlSrc);
document.getElementsByTagName('head')[0].appendChild(script);
</script>
      方法3:通过jQuery的内置方法调用

         <script type="text/javascript">
function callBackThree(data){
console.log(data);
}
$.getJSON('http://localhost/json.php?call=?',function(data){
console.log(data);
});
</script>
    方法4:ajax形式

        <script type="text/javascript">
$.ajax({
url:'http://localhost/json.php',
type:'POST',
dataType:'jsonp',
jsonp:'call',
jsonpCallback:'callBackFour',
success:function(data){
console.log("success返回值",data);
},
error:function(errorMsg){
console.log(errorMsg);
}
});
function callBackFour(data){
console.log(data);
}
</script>

    以上的4种方法是基本上大家用的最多的方法,当然如果可行的方法是将php文件直接写成接口的形式,当请求时添加访问的参数,直接获取相应的数据


  2.代理

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

  3、PHP端修改header(XHR2方式)

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

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

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