27 March 2014

学习自:说说JSON和JSONP,也许你会豁然开朗,含jQuery用例

条件


  1. 由于JS的同源策略限制,无法通过AJAX向其他域发送请求;
  2. 凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<script><img><iframe>
  3. JS可动态为当前DOM结构增加和删除节点;
  4. 当浏览器请求一个JS文件时,会执行请求返回的内容。

实现方法


基于上述4个条件,我们可以这样做:

  • 在HTML页面中加入:<script type="text/javascript" src="http://localhost/jsonp.php"></script>
  • 后台jsonp.php页面:echo 'alert("Hi, men.")';

载入HTML页面就会看到提示框。

如果服务端输出一个函数调用(该函数为JS客户端所期望的函数),参数为服务端处理好的JSON数据,那么不就能够很好地实现跨域请求了么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>Test</title>
        <!--<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>-->
        <script type="text/javascript">
        var sayHi = function (data) {
            alert('Hi, ' + data.name);
        }
        var jsonpUrl = 'Http://localhost/jsonp.php?callback=sayHi';
        var script = document.createElement('script');
        script.setAttribute('src', jsonpUrl);
        document.getElementsByTagName('head')[0].appendChild(script);
        </script>
    </head>
<body>
</body>
</html>
1
2
3
4
5
<?php
if (isset($_GET['callback'])) {
    echo $_GET['callback'].'('.json_encode(['name'=>'rokety']).')';
}
?>

JQuery使用Ajax发送JSONP请求


其实JQuery是将上面讲到的实现方法包装进了Ajax中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>Test</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script type="text/javascript">
        function sayHi (data) {
            alert('Hi, ' + data.name + '. Your profile: ' + data.description);
        }
        jQuery(document).ready(function(){
            $.ajax({
                type : "GET",
                url : "http://localhost/jsonp.php",
                dataType : "jsonp",
                data : "name=rokety",
                jsonp : "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
                jsonpCallback:"sayHi",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
                err : function () {
                    alert('Request Fail!');
                }
            });
        });
        </script>
    </head>
<body>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$user = [
    'rokety' => 'A programmer!'
];

if (isset($_GET['callback']) && isset($_GET['name'])) {
    if (isset($user[$_GET['name']])) {
        echo $_GET['callback'].'('.json_encode(
            [
                'name'=>$_GET['name'],
                'description'=>$user[$_GET['name']]
            ]
        ).')';
    } else {
        echo $_GET['callback'].'('.json_encode(
            [
                'name'=>$_GET['name'],
                'description'=>'unknow person!'
            ]
        ).')';
    }

}
?>

注意


JSONP并不支持POST请求,根据实现原理也应该能看出这一点。