文档章节

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
博文 90
码字总数 25222
作品 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
JQuery + JsonP 解决跨域请求

什么是跨域 跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就...

刘引惟
2016/11/23
75
0
JSONP原理优缺点(只能GET不支持POST)

JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都 可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕...

BearCatYN
2015/06/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

C++ std::thread

C++11提供了std::thread类来表示一个多线程对象。 1,首先介绍一下std::this_thread命名空间: (1)std::this_thread::get_id():返回当前线程id (2)std::this_thread::yield():用户接口...

yepanl
16分钟前
0
0
Nignx缓存文件与动态文件自动均衡的配置

下面这段nginx的配置脚本的作用是,自动判断是否存在缓存文件,如果有优先输出缓存文件,不经过php,如果没有,则回到php去处理,同时生成缓存文件。 PHP框架是ThinkPHP,最后一个rewrite有关...

swingcoder
20分钟前
0
0
20180920 usermod命令与用户密码管理

命令 usermod usermod 命令的选项和 useradd 差不多。 一个用户可以属于多个组,但是gid只有一个;除了gid,其他的组(groups)叫做扩展组。 usermod -u 1010 username # 更改用户idusermod ...

野雪球
22分钟前
0
0
Java网络编程基础

1. 简单了解网络通信协议TCP/IP网络模型相关名词 应用层(HTTP,FTP,DNS等) 传输层(TCP,UDP) 网络层(IP,ICMP等) 链路层(驱动程序,接口等) 链路层:用于定义物理传输通道,通常是对...

江左煤郎
28分钟前
0
0
使用xtrabackup完成远程备份

转载收藏,以防丢失 需求 Can I backup remote databases from my local server02-27-2013, 06:17 AMHi, I am using mysqldump so far for taking daily backups of my Production datab......

阿dai
33分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部