Ajax-跨域

来源:互联网 发布:java解析syslog 编辑:程序博客网 时间:2024/06/05 16:33

一个域名地址的组成:
这里写图片描述
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对方的资源。当协议、子域名、主域名、端口号中任意一个不同时,都算做不同域,不同域之间相互请求资源,就算做“跨域”。

跨域解决方法:
1、代理(后台解决);
2、JSONP(针对 GET 方式);
3、XHR2(IE10以下不支持)。

JSONP

Jsonp原理:
首先在客户端注册一个callback, 然后把callback的名字传给服务器。此时,服务器先生成 json 数据。然后以 javascript 语法的方式,生成一个function,function 名字就是传递上来的callback的名字。最后将事先生成的 json 数据直接以参数的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。客户端浏览器解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里。

JSONP实例:百度搜索

<!DOCTYPE html><html>    <head>        <meta charset="utf-8" />        <title></title>        <style type="text/css">            *{ margin: 0; padding: 0;}            #q{ display: block; width: 300px; height: 30px; border: 1px solid #e1e1e1; margin: 50px auto 0;}            #ul1{ list-style: none; width: 300px; border: 1px solid #EDEDED; margin: -1px auto 0; display: none;}            #ul1 li a{ display: block; height: 30px; line-height: 30px; padding: 0 5px; text-decoration: none; color: #666;}            #ul1 li a:hover{ background: #ededed;}        </style>        <script type="text/javascript">            function jsonpCallback(data){                var oUl=document.getElementById("ul1");                var html='';                if (data.s.length) {                    oUl.style.display='block';                    for (var i=0; i<data.s.length; i++) {                        html+='<li><a target="_blank" href="https://www.baidu.com/s?wd='+ data.s[i] +'">'+ data.s[i] +'</a></li>';                    }                    oUl.innerHTML=html;                }else{                    oUl.style.display='none';                }            }            window.onload=function(){                var oQ=document.getElementById("q");                var oUl=document.getElementById("ul1");                oQ.onkeyup=function(){                    if (this.value!='') {                        var oScript=document.createElement('script');                        oScript.src='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?json=1&cb=jsonpCallback&wd='+this.value;                        document.body.appendChild(oScript);                    }else{                        oUl.style.display='none';                    }                }                document.onclick=function(){                    oUl.style.display='none';                }            }        </script>    </head>    <body>        <input id="q" type="text" />        <ul id="ul1">            <!--<li><a target="_blank" href="#">11</a></li>            <li><a target="_blank" href="#">22</a></li>            <li><a target="_blank" href="#">33</a></li>-->        </ul>    </body></html>

JSONP并不是所有跨域通信需求的万灵药,它有一些缺陷。
第一,也是最重要的一点,没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。

JQ应用JSONP的实例:上文中的案例,当把GET方法中请求的url由”http://localhost/ajaxdemo/server.php“改为”http://127.0.0.1/ajaxdemo/server.php“之后,就出现了跨域问题。

解决之后的前端代码:

<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.js"></script><script>$(document).ready(function(){    $('#search').click(function(){        $.ajax({            type:"GET",            url:"http://127.0.0.1/ajaxdemo/server.php?number=" + $('#keyword').val()+"&"+ Math.random(),            dataType:'jsonp',            jsonp:'callback',            success:function(data){                if (data.success) {                    $('#searchResult').html(data.msg);                }else{                    $('#searchResult').html('出了错误:'+data.msg);                }            },            error:function(jqXHR){                alert("发生错误:" + jqXHR.status);            }        });    })})</script>

可以看出前端代码仅修改增加了以下代码字段:

dataType:'jsonp',jsonp:'callback',

服务端代码修改后为:

<?phpheader("Content-Type: application/json;charset=utf-8"); $staff = array    (        array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),        array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),        array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")    );if ($_SERVER["REQUEST_METHOD"] == "GET") {    search();} elseif ($_SERVER["REQUEST_METHOD"] == "POST"){    create();}function search(){    $jsonp=$_GET["callback"];    if (!isset($_GET["number"]) || empty($_GET["number"])) {        echo $jsonp.'({"success":false,"msg":"参数错误"})';        return;    }    global $staff;    $number = $_GET["number"];    $result = '{"success":false,"msg":"没有找到员工"}';    foreach ($staff as $value) {        if ($value["number"] == $number) {            $result = $jsonp.'({"success":true,"msg":"找到员工:员工编号:' . $value["number"] .                             ',员工姓名:' . $value["name"] .                             ',员工性别:' . $value["sex"] .                             ',员工职位:' . $value["job"] . '"})';            break;        }    }    echo $result;}?>

XHR2

HTML5中提供的XMLHttpRequest Level2(即XHR2)已经实现了跨域访问。但ie10以下不支持。

只需要在服务端填上以下响应头:

header("Access-Control-Allow-Origin:*");/*星号表示所有的域都可以接受,*/header("Access-Control-Allow-Methods:GET,POST");

总结:代理实现最麻烦,但使用最广泛,任何支持AJAX的浏览器都可以使用这种方式。JSONP相对简单,但只支持GET方式调用。XHR2最简单,但只支持HTML5,如果是移动端开发,可以选择使用XHR2。

0 0
原创粉丝点击