文档章节

jsonp 原理解析

dubox
 dubox
发布于 2017/05/04 12:19
字数 811
阅读 7
收藏 0

以前用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’); 来解决,不加也不影响。。。

© 著作权归作者所有

共有 人打赏支持
dubox
粉丝 3
博文 94
码字总数 27160
作品 0
西安
程序员
私信 提问
由Java爬虫所想到的

爬虫,听起来似乎很高端,然而也就那么回事,有很多爬虫框架,Java实现的有crawler4j,WebCollector,webMagic,Python实现的最著名的应该是Scrapy,工作中用到,但是没用什么爬虫框架,整个...

开源中国刘德华
2016/06/02
100
0
Ajax+Spring MVC实现跨域请求(JSONP)

JSONP解释 在解释JSONP之前,我们需要了解下”同源策略“这个概念,这对理解跨域有帮助。基于安全的原因,浏览器是存在同源策略机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源...

熊大熊二
2015/09/18
416
2
JSONP跨域的原理解析

JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页...

武文海
2016/03/21
24
0
SegmentFault 技术周刊 Vol.33 - 什么是 JSON ?

JSON 的全称是JavaScript Object Notation,可以翻译为 JavaScript 对象表示法,即将一个 Object 以文本的方式给记录下来。 根据 ECMA-404 标准: JSON is a text format that facilitates s...

keke
2017/09/07
0
0
Jquery跨域获得Json

这两天用 Jquery 跨域取数据的时候,经常碰到 invalid label 这个错误,十分的郁闷,老是取不到服务器端发送回来的 json 值, 一般跨域用到的两个方法为:$.ajax 和$.getJSON 最后,仔细安静...

吞吞吐吐的
2017/10/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

小白带你认识netty(三)之NioEventLoop的线程(或者reactor线程)启动(一)

在第一章中,我们看关于NioEventLoopGroup的初始化,我们知道了NioEventLoopGroup对象中有一组EventLoop数组,并且数组中的每个EventLoop对象都对应一个线程FastThreadLocalThread,那么这个...

天空小小
今天
3
0
PHP动态扩展Redis模块

查看已有模块 [root@test-a ~]# /usr/local/php/bin/php -m[PHP Modules]bz2Core...zlib[Zend Modules] 下载包,解压,生成configure文件 [root@test-a ~]# cd /usr/local/src/[ro......

野雪球
今天
4
0
在Ignite中使用线性回归算法

在本系列前面的文章中,简单介绍了一下Ignite的机器学习网格,下面会趁热打铁,结合一些示例,深入介绍Ignite支持的一些机器学习算法。 如果要找合适的数据集,会发现可用的有很多,但是对于...

李玉珏
今天
5
0
Mybatis应用学习——简单使用示例

1. 传统JDBC程序中存在的问题 1. 一个简单的JDBC程序示例: public class JDBCDemo {public static void main(String[] args) {Connection con=null;PreparedStatement statemen...

江左煤郎
今天
4
0
使用JavaScript编写iOS应用业务逻辑

JSAUIKitCocoa使你可以使用JavaScript编写对性能要求不高但可能变动性很大的iOS应用的业务逻辑部分,View组件、需要多线程支持的Model等则直接使用原生对象。 编写方式与React Native相似,但...

neal01
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部