详细分析jsonp的原理和实现方式


Posted in Javascript onNovember 20, 2017

针对跨域问题,本文主要给大家详细分析一下jsonp的原理,希望能够给你提供到帮助。

详细分析jsonp的原理和实现方式

一:跨域问题。

详细分析jsonp的原理和实现方式

二,跨域产生的原因

Js是不能跨域请求。出于安全考虑,js设计时不可以跨域。

什么是跨域:

1、域名不同时。

2、域名相同,端口不同。

只有域名相同、端口相同时,才可以访问。

可以使用jsonp解决跨域问题。

三,跨域失败的案例 3.1,同源策略

首先基于安全的原因,浏览器是存在同源策略这个机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。看起来不知道什么意思,实践一下就知道了。

3.2,随便建两个网页

一个端口是2698,一个2701,按照定义它们是不同源的。

详细分析jsonp的原理和实现方式

3.3,用jQuery发起不同源的请求

在2698端口的网页上添加一个按钮,Click事件随便发起两个向端口为2701域的请求。

$("#getOtherDomainThings").click(function () {
$.get("http://localhost:2701/Scripts/jquery-1.4.4.min.js", function (data) {
console.log(data)
})

$.get("http://localhost:2701/home/index", function (data) {
console.log(data)
})
})

根据同源策略,很明显会悲剧了。浏览器会阻止,根本不会发起这个请求。(not allowed by Access-Control-Allow-Origin)

详细分析jsonp的原理和实现方式

OK,原来jsonp是要解决这个问题的。

换句话就是说在一个src中或者一个url中直接去请求了另一个项目的json数据。

例如在端口是8080的项目中的页面的url中直接去请求了一个http://localhost:8081/category.json这个语句,而这个category.json就在8081的webapp的目录下,就会产生跨域请求的提示。

四,跨域的解决方法 4.1,启发

我们有时候在项目中经常能看到这样的代码

<script type="text/javascript" src="https://com/seashell/weixin/js/jquery.js"></script>

这样即使不在同一个项目中,也可以请求成功。就是利用了这个漏洞,或者说是技术吧,来实现的宽裕的请求。

4.2,方法(案例一) 4.2.1,利用script获取不同源的json

既然它叫jsonp,很明显目的还是json,而且是跨域获取。根据上面的分析,很容易想到:利用js构造一个script标签,把json的url赋给script的scr属性,把这个script插入到dom里,让浏览器去获取。实践:

function CreateScript(src) {
 $("<script><//script>").attr("src", src).appendTo("body")
}

添加一个按钮事件来测试一下:

$("#getOtherDomainJson").click(function () {
 $.get('http://localhost:2701/home/somejson', function (data) {
  console.log(data)
 })
})

详细分析jsonp的原理和实现方式

首先,第一个浏览器,http://localhost:2701/home/somejson这个Url的确是存在一个json的,而且在 2698网页上用script标签来请求这个2701这个Url也是200OK的,但是最下面报js语法错误了。原来用script标签加载完后,会立即 把响应当js去执行,很明显{"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"}不是合法的js语句。

4.2.2,利用script获取异域的jsonp

显然,把上面的json放到一个回调方法里是最简单的方法。例如,变成这样:

详细分析jsonp的原理和实现方式

如果存在jsonpcallback这个方法,那么jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})就是合法的js语句。

在这里需要注意的就是在原来的json格式的数据{"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"}要封装成jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})这样一个脚本,这样才会被回调的时候解析到,否则解析也是失败的。

由于服务器不知道客户端的回调是什么,不可能hard code成jsonpcallback,所以就带一个QueryString让客户端告诉服务端,回调方法是什么,当然,QueryString的key要遵从服务端的约定,上面的是”callback“。

添加回调函数:

function jsonpcallback(json) {
 console.log(json)
}

把前面的方法稍微改改参数:

$("#getJsonpByHand").click(function () {
 CreateScript("http://localhost:2701/home/somejsonp?callback=jsonpcallback")
})

详细分析jsonp的原理和实现方式

200OK,服务器返回jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的 东方"}),我们也写了jsonpcallback方法,当然会执行。OK顺利获得了json。没错,到这里就是jsonp的全部。

4.2.3,利用jQuery获取jsonp

上面的方式中,又要插入script标签,又要定义一个回调,略显麻烦,利用jQuery可以直接得到想要的json数据,同样是上面的jsonp:

$("#getJsonpByJquery").click(function () {
$.ajax({
url: 'http://localhost:2701/home/somejsonp',
dataType: "jsonp",
jsonp: "callback",
success: function (data) {
console.log(data)
}
})
})

得到的结果跟上面类似。

4.2.4,总结

一句话就是利用script标签绕过同源策略,获得一个类似这样的数据,jsonpcallback是页面存在的回调方法,参数就是想得到的json。

jsonpcallback({"Email":"zhww@outlook.com","Remark":"我来自遥远的东方"})

4.3,案例二 4.3.1,简单应用

程序A中sample的部分代码:

<script type="text/javascript">
//回调函数
function callback(data) {
alert(data.message);
}
</script>
<script type="text/javascript" src="http://localhost:20002/test.js"></script>

程序B中test.js的代码:
1 //调用callback函数,并以json数据形式作为阐述传递,完成回调
2 callback({message:"success"});
这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义吧。

一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

4.3.2,简单应用的升级以一

程序A中sample的部分代码:

<script type="text/javascript">
function callback(data) {
alert(data.message);
}
//添加<script>标签的方法
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function(){
addScriptTag("http://localhost:20002/test.js");
}
</script>

程序B的test.js代码不变,我们再执行下程序,是不是和原来的一样呢。如果我们再想调用一个远程服务的话,只要添加addScriptTag方法,传入远程服务的src值就可以了。这里说明下为什么要将addScriptTag方法放入到window.onload的方法里,原因是addScriptTag方法中有句document.body.appendChild(script);,这个script标签是被添加到body里的,由于我们写的javascript代码是在head标签中,document.body还没有初始化完毕呢,所以我们要通过window.onload方法先初始化页面,这样才不会出错。

这样这个http://localhost:20002/test.js路径就可以动态的变化了。

4.3.3,简单应用的升级二

上面的例子是最简单的JSONP的实现模型,不过它还算不上一个真正的JSONP服务。我们来看一下真正的JSONP服务是怎么样的,比如Google的ajax搜索接口:http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=?&callback=?

q=?这个问号是表示你要搜索的内容,最重要的是第二个callback=?这个是正如其名表示回调函数的名称,也就是将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调。有点罗嗦了,还是看看实现代码吧:

<script type="text/javascript">//添加<script>标签的方法function addScriptTag(src){ var script = document.createElement('script');script.setAttribute("type","text/javascript");script.src = src;document.body.appendChild(script);}window.onload = function(){//搜索apple,将自定义的回调函数名result传入callback参数中addScriptTag("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=apple&callback=result");}//自定义的回调函数resultfunction result(data) {//我们就简单的获取apple搜索结果的第一条记录中url数据alert(data.responseData.results[0].unescapedUrl);}</script>

这个result方法是自己定义的,可能服务器上有千千万万个类似于result 的回调函数,但是我现在要的就是result而不是其它的方法,所以在这里自己定义回调方法。而不是写死的。可能下一次我就改成result1,result2,result3,等了只要自己把回调方法的名称改一下就行了。

4.4.4,jquery对jsonp的支持

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法(详细可以参考http://api.jquery.com/jQuery.getJSON/)。那我们就来修改下程序A的代码,改用jQuery的getJSON方法来实现(下面的例子没用用到向服务传参,所以只写了getJSON(url,[callback])):

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
 $.getJSON("http://localhost:20002/MyService.ashx?callback=?",function(data){
  alert(data.name + " is a a" + data.sex);
 });
</script>

结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个问号是内部自动生成的一个回调函数名。这个函数名大家可以debug一下看看,比如jQuery17207481773362960666_1332575486681。

当然,加入说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现(参数较多,详细可以参考http://api.jquery.com/jQuery.ajax)。先来看看如何实现吧:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
 $.ajax({
  url:"http://localhost:20002/MyService.ashx?callback=?", 
  dataType:"jsonp",
  jsonpCallback:"person",
  success:function(data){
   alert(data.name + " is a a" + data.sex);
  }
 });
</script>

没错,jsonpCallback就是可以指定我们自己的回调方法名person,远程服务接受callback参数的值就不再是自动生成的回调名,而是person。dataType是指定按照JSOPN方式访问远程服务。

以上就是本次分享关于jsonp的原理的全部内容和代码,有问题的朋友在下方留言讨论吧。

Javascript 相关文章推荐
JavaScript 学习点滴记录
Apr 24 Javascript
js 实现打印网页中定义的部分内容的代码
Apr 01 Javascript
JavaScript实现自动对页面上敏感词进行屏蔽的方法
Jul 27 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
Aug 04 Javascript
js实现左侧网页tab滑动门效果代码
Sep 06 Javascript
JavaScript面试开发常用的知识点总结
Aug 08 Javascript
分分钟玩转Vue.js组件(二)
Mar 01 Javascript
使用Vue开发一个实时性时间转换指令
Jan 17 Javascript
JavaScript使用小插件实现倒计时的方法讲解
Mar 11 Javascript
JavaScript this关键字指向常用情况解析
Sep 02 Javascript
JavaScript实现网页动态生成表格
Nov 25 Javascript
详解vue中使用transition和animation的实例代码
Dec 12 Vue.js
three.js中文文档学习之通过模块导入
Nov 20 #Javascript
JS写XSS cookie stealer来窃取密码的步骤详解
Nov 20 #Javascript
浅谈Vue SSR 的 Cookies 问题
Nov 20 #Javascript
three.js中文文档学习之创建场景
Nov 20 #Javascript
Vue 中批量下载文件并打包的示例代码
Nov 20 #Javascript
VueJs 搭建Axios接口请求工具
Nov 20 #Javascript
Vue2 SSR渲染根据不同页面修改 meta
Nov 20 #Javascript
You might like
模仿OSO的论坛(一)
2006/10/09 PHP
php数据库密码的找回的步骤
2011/01/12 PHP
使用ThinkPHP自带的Http类下载远程图片到本地的实现代码
2011/08/02 PHP
基于OpenCart 开发支付宝,财付通,微信支付参数错误问题
2015/10/01 PHP
编写PHP脚本清除WordPress头部冗余代码的方法讲解
2016/03/01 PHP
100行PHP代码实现socks5代理服务器
2016/04/28 PHP
PHP文件管理之实现网盘及压缩包的功能操作
2017/09/20 PHP
docker-compose部署php项目实例详解
2019/07/30 PHP
PHP替换Word中变量并导出PDF图片的实现方法
2020/11/26 PHP
JS实现浏览器菜单命令
2006/09/05 Javascript
JQuery为textarea添加maxlength属性并且兼容IE
2013/04/25 Javascript
node.js中的fs.createWriteStream方法使用说明
2014/12/17 Javascript
jQuery插件Tmpl的简单使用方法
2015/04/27 Javascript
JSON字符串和对象之间的转换详解
2015/05/26 Javascript
jQuery实现的自适应焦点图效果完整实例
2016/08/24 Javascript
微信小程序 在Chrome浏览器上运行以及WebStorm的使用
2016/09/27 Javascript
详解基于javascript实现的苹果系统底部菜单
2016/12/02 Javascript
bootstrap下拉菜单使用方法解析
2017/01/13 Javascript
详解vue项目首页加载速度优化
2017/10/18 Javascript
在vue中使用css modules替代scroped的方法
2018/03/10 Javascript
vue 使用async写数字动态加载效果案例
2020/07/18 Javascript
Element Notification通知的实现示例
2020/07/27 Javascript
使用js和canvas实现时钟效果
2020/09/08 Javascript
[10:42]Team Liquid Vs Newbee
2018/06/07 DOTA
用python 批量更改图像尺寸到统一大小的方法
2018/03/31 Python
python 多线程重启方法
2019/02/18 Python
python psutil监控进程实例
2019/12/17 Python
顶丰TOPPIK台湾官网:增发纤维假发,告别秃发困扰
2018/06/13 全球购物
中学生学习生活的自我评价
2013/10/26 职场文书
干部选拔任用方案
2014/05/26 职场文书
民族团结先进个人事迹材料
2014/06/02 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
工作失误检讨书范文
2015/01/26 职场文书
大学体育课感想
2015/08/10 职场文书
家长会后的感想
2015/08/11 职场文书
php字符串倒叙
2021/04/01 PHP