jsonp 原理解析
博客专区 > dubox 的博客 > 博客详情
jsonp 原理解析
dubox 发表于7个月前
jsonp 原理解析
  • 发表于 7个月前
  • 阅读 5
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

以前用jsonp 服务端都是请求别人的api 例如:百度,所以也很少注意服务端的写法。

今天用jqmobi 的 jsonP 函数请求自己的API 结果报错:SyntaxError: missing ; before statement

ee

 

但是我反复检查我的json字符串没有发现问题,十分郁闷

查了网上的一些文章 说是 要加一对()写成 “(“+data+”)”

于是加了对括弧,果然不报错了,但有一个警告:Resource interpreted as Script but transferred with MIME type text/html ;而且问题依然存在

看到script 有些不解, 不是 json吗?

于是打算去看看源码:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

<script type="text/javascript">
       /**
        * Execute a jsonP call, allowing cross domain scripting
        * options.url - URL to call
        * options.success - Success function to call
        * options.error - Error function to call
            ```
            $.jsonP({url:"mysite.php?callback=?&foo=bar",success:function(){},error:function(){}});
            ```

        * @param {Object} options
        * @title $.jsonP(options)
        */
        $.jsonP = function(options) {
            if (isWin8) {
                options.type = "get";
                options.dataType = null;
                return $.get(options);
            }
            var callbackName = "jsonp_callback" + (++_jsonPID); //定义回调函数的 函数名(若不指定,则使用这个)
            var abortTimeout = "",
                context, callback;
            var script = document.createElement("script");  //创建请求服务器的 script对象
            var abort = function() {
                $(script).remove();
                if (window[callbackName])
                    window[callbackName] = empty;
            };
            
            /***重点***
            定义 回调函数 
            而服务器端就要输出调用这个函数的一段代码(js代码)
            即:'callbackName(data)'
            callbackName 就是url中callback的值
            data 是你想要发送到本地的数据
            *****/
            window[callbackName] = function(data) {
            
                clearTimeout(abortTimeout);
                $(script).remove();
                delete window[callbackName];
                options.success.call(context, data);    //这里执行你自己定义的 请求成功后的回调函数
            };
            
            //下面这段 是处理URL的 
            if (options.url.indexOf("callback=?") !== -1) {
                script.src = options.url.replace(/=\?/, "=" + callbackName);
            } else {

                callback = options.jsonp ? options.jsonp : "callback";                
                if (options.url.indexOf("?") === -1) {
                    options.url += ("?" + callback + "=" + callbackName);
                }
                else {
                    if(options.url.indexOf("callback=")!==-1){

                        var searcher="callback=";
                        var offset=options.url.indexOf(searcher)+searcher.length;
                        var amp=options.url.indexOf(offset);
                        if(amp===-1)
                            amp=options.url.length;
                        var oldCB=options.url.substr(offset,amp);
                        options.url=options.url.replace(searcher+oldCB,searcher+callbackName);
                        oldCB=oldCB.replace("window.","");
                        options.success=window[oldCB];
                    }
                    else {
                        options.url += ("&" + callback + "=" + callbackName);
                    }
                }
                script.src = options.url;   //将处理过的URL 作为script的src值
            }
            if (options.error) {
                script.onerror = function() {
                    clearTimeout(abortTimeout);
                    options.error.call(context, "", "error");
                };
            }
            $("head").append(script);   //将script插入到页面head中,载入成功后你在服务端输出的js代码就被执行了
            if (options.timeout > 0)
                abortTimeout = setTimeout(function() {
                    options.error.call(context, "", "timeout");
                }, options.timeout);
            return {};
        };

</script>

以上是jqmobi中jsonP函数的源码

我在其中加了一些注释 ,希望没有误导人。。。哈哈

这样就清楚了

其实是 在页面head里插入一个<script></script>,

用你的请求地址做script的 src 从而实现 异步 跨域 请求

而链接中的callback参数值将作为回调函数的名字,所以服务端这样写就可以了(php为例):

php default" style="overflow:auto;white-space:nowrap;width:590px;">

1

<!--?php echo $_GET['callback'].'('.json_encode($data).")"; ?-->

原来jsonp是这么回事儿。。。

现在再去看百度的API 发现 直接在浏览器访问API输出的是json,但当你在地址中加入callback参数时它就会输出像上面那样的js代码。。。

顿时觉得 好坑啊。。。

 

另外,上面提到的警告:Resource interpreted as Script but transferred with MIME type text/html

可以在服务端加上一句  header(‘Content-type: application/x-javascript’); 来解决,不加也不影响。。。

标签: JavaScript
共有 人打赏支持
粉丝 2
博文 52
码字总数 12702
×
dubox
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: