文档章节

jsonp 原理解析

dubox
 dubox
发布于 2017/05/04 12:19
字数 811
阅读 7
收藏 0
点赞 0
评论 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
粉丝 2
博文 75
码字总数 21359
作品 0
西安
程序员
由Java爬虫所想到的

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

开源中国刘德华 ⋅ 2016/06/02 ⋅ 0

Ajax+Spring MVC实现跨域请求(JSONP)

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

熊大熊二 ⋅ 2015/09/18 ⋅ 2

JSONP原理优缺点(只能GET不支持POST)

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

BearCatYN ⋅ 2015/06/04 ⋅ 0

JSONP跨域的原理解析

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

武文海 ⋅ 2016/03/21 ⋅ 0

JQuery + JsonP 解决跨域请求

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

刘引惟 ⋅ 2016/11/23 ⋅ 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

Jquery跨域获得Json

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

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

JSONP实现跨域

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

hanzhankang ⋅ 2014/01/23 ⋅ 0

jquery的ajax和getJson跨域获取json数据

目前浏览器端跨域访问常用的两种方法有两种: 1、通过jQuery的ajax进行跨域,这其实是采用的jsonp的方式来实现的。 jsonp是英文json with padding的缩写。它允许在服务器端生成script tags至...

sunny5156 ⋅ 2013/07/25 ⋅ 1

JSONP跨域GET请求解决Ajax跨域访问问题

需求:需要前端web页面异步调用后台的Webservice方法返回信息。 实现方法有多种,本例采用jQuery+Ajax,完成后,在本地调试了一切ok,但是部署到服务器上以后就出现问题了,后台服务调用没有响...

文文1 ⋅ 2015/12/04 ⋅ 2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Python爬虫,抓取淘宝商品评论内容

作为一个资深吃货,网购各种零食是很频繁的,但是能否在浩瀚的商品库中找到合适的东西,就只能参考评论了!今天给大家分享用python做个抓取淘宝商品评论的小爬虫! 思路 我们就拿“德州扒鸡”...

python玩家 ⋅ 11分钟前 ⋅ 0

MySQL 内核深度优化

MYSQL数据库适用场景广泛,相较于Oracle、DB2性价比更高,Web网站、日志系统、数据仓库等场景都有MYSQL用武之地,但是也存在对于事务性支持不太好(MySQL 5.5版本开始默认引擎才是InnoDB事务...

java高级架构牛人 ⋅ 33分钟前 ⋅ 0

用户登录信息-钉子效果(基于jquery2.0)

本js效果使用jquery2.0,清晰的分解用户登录信息的(钉子效果),该效果直接用在作者网站(www.phpkhbd.com)上。 里面的难点有:定时器,延时。 大致效果如下: 一开始: 鼠标放上去的时候:...

宁哥实战课堂 ⋅ 35分钟前 ⋅ 0

解决yum安装报错Protected multilib versions

使用yum安装报错Protected multilib versions原因是因为多个库不能共存,不过更新的话也并不行,但是可以在安装命令后面加上如下一段命令: --setopt=protected_multilib=false 案例: 比如需...

北岩 ⋅ 46分钟前 ⋅ 0

为什么要学习Typescript???

简单来说 目前的typescript就是未来的javascript 为什么?? 这要从ECMA-262标准的第4版说起 对了 我们说的ES5 其实是ECMAScript3.1这个替代性建议被扶正了而已... 那么 第4版标准是什么? 看看...

hang1989 ⋅ 50分钟前 ⋅ 0

linux安装ipfs

一、下载ipfs # cd /usr/local/ipfs/ # wget https://dist.ipfs.io/go-ipfs/v0.4.15/go-ipfs_v0.4.15_linux-amd64.tar.gz # tar -zxvf go-ipfs_v0.4.15_linux-amd64.tar.gz 二、安装ipfs # ......

八戒八戒八戒 ⋅ 56分钟前 ⋅ 0

jvm程序执行慢诊断手册

生产环境最多的几种事故之一就是程序执行慢,如果是web服务的话,表现就是响应时间长。本文分享,从业多年形成的排查守则。 诊断步骤 系统资源查看 首先是系统资源查看,而且必须是在第一步。...

xpbob ⋅ 56分钟前 ⋅ 0

YII2 advanced 高级版本项目搭建-添加API应用以及多应用

一、YII安裝 安裝yii可以用composer安裝,也可以在yii中文社区下载归档文件安装 composer安装就不介绍了,因为要安装composer,比较麻烦,当然安装了composer是最好的,以后安装yii的插件要用...

botkenni ⋅ 57分钟前 ⋅ 0

在jdk1.8的环境下模拟永久代内存溢出

相信不少小伙伴在看深入理解Java虚拟机的时候,作者给我们举例一个demo来发生PermGen space 1、通过List不断添加String.intern(); 2、通过设置对应的-XX:PermSize与-XX:MaxPermSize(更快看到...

虾几把写 ⋅ 今天 ⋅ 0

开发OpenDaylight组件的完整流程

在前面介绍学习了OpenDaylight的几个重要模块后,这里再来介绍下完整开发一个模块的过程。 OSGI的bundles提供被其他OSGI组件调用的服务。这个教程中展示的是Data Packet Service去解析数据包...

wangxuwei ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部