对于JSON和JSONP,应该都不陌生,咳咳,不过最初对JSONP有点误解,以为是JSON的另外一个别名,其实二者风马牛不相及。
谈到Json和jsonp就不可避免要提到跨域这个话题了,以前对跨域的理解都是比较模糊的,还以为域名不同就是跨域了,那太狭隘了。非同源请求,均为跨域。
不过为什么会出现跨域?出于浏览器的同源策略限制,浏览器会拒绝跨域请求。
严格的说,浏览器并不是拒绝所有的跨域请求,实际上拒绝的是跨域的读操作。浏览器的同源限制策略是这样执行的:
通常浏览器允许进行跨域写操作(Cross-origin writes),如链接,重定向;
通常浏览器允许跨域资源嵌入(Cross-origin embedding),如 img、script 标签(主要是有src);
通常浏览器不允许跨域读操作(Cross-origin reads)。*
等等,上面咋又来了个同源策略,本是同根生,相煎何太急啊。
大家互相开开心心的走亲访友多好。哼,谁知道你是我亲戚还是坏人,万一你来我家是想偷小鱼干的呢?还开开心心,本喵不得哭死啊。 同源策略 (Same-Origin Policy) 最早由 Netscape 公司提出, 所谓同源就是要求, 域名, 协议, 端口相同. 非同源的脚本不能访问或者操作其他域的页面对象(如DOM等). 作为著名的安全策略, 虽然它只是一个规范, 并不强制要求, 但现在所有支持 javaScript 的浏览器都会使用这个策略. 以至于该策略成为浏览器最核心最基本的安全功能, 如果缺少了同源策略, web的安全将无从谈起.(这段文字是cv的)
这下好了,同源策略下的web世界, 域的壁垒高筑, 保证各个网页相互独立, 互相之间不能直接访问, iframe, ajax 均受其限制, 而script标签不受此限制.
注: 如非特别说明, 均指非CORS的, 普通跨域请求.
咳咳,我们讲json呢,扯远了,快回来
哎,哎,相公,别敲我脑袋瓜子啊,疼,敲笨了你就只能有个笨媳妇。人家这不是麻溜的回来了嘛,你倒是给我说说json和惊悚有啥不同。
“你知道啥是json么?”
“本大喵当然知道,json是一种数据格式”
“手写一段给本汪瞅瞅”
// 描述一个人
var person = {
"Name": "大宝",
"Age": 1,
"Company": "IBM",
"Engineer": true
}
“算你上次没逃课,那你给我说说,这个json有啥要注意的地方?”
“咦,json不就简单的数据格式吗,有啥要注意?”
“就知道你上次没认真听,肯定开小差了,今晚回去小鱼干没了。”
“喵呜~~~人家错了,你再说一遍吧?嘤嘤嘤”
“记得下次考你,看仔细了”
■ ■■■■
这会儿带你认识认识jsonp了,看会儿惊悚片
“喵喵,你知道ajax么?”
“听过,但是不太了解”
“推荐一个blog,你去看看,下次讲给我听听,答的好有小鱼干吃哟”
“猴!得令”
Ajax直接请求普通文件存在跨域无权限访问的问题,无论是静态页面还是动态页面,web服务,WCF(喵呜,这是啥?),但是在web页面上调用js文件时不受到跨域的影响(凡是拥有src属性的都有跨域的神奇能力),所以可以通过在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理,而处理这些数据的格式可以是json,而且json还被原生js支持,很完美了。
方案如下:
Web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件,客户端在对json文件成功调用之后,获得了自己所需的数据,这就是jsonp,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据,这样客户端就可以随意定制函数来自动处理返回数据。
具体实现示例:
喵喵:远程服务器。cat.com
汪汪:本地服务器.dag.com
1 miaomiao.js是cat.com根目录下的一个js文件。 代码如下
<pre style="margin: 0.5em 0px; padding: 0.4em 0.6em; border-radius: 8px; background: rgb(248, 248, 248); box-sizing: border-box;">alert(‘喵呜,我是喵喵’);</pre>
Jsonp.html是dag.com下的一个页面:
这里会弹出弹窗,现实跨域成功。
2 在jsonp.html页面定义一个函数。然后在远程文件miaomiao.js中传入数据进行调用。
miaomiao.js:
localHandler({"result":"我是远程猫js带来的数据"});
运行之后,显示本地调用成功,并且获取数据。但是如何让miaomiao知道它调用的dog函数叫什么呢?毕竟附近的dog太多了。
3 喵喵和汪汪想了一个办法,如果汪汪想要调用喵喵,就在返回的骨头上加一个标志,说我想调用XXX函数的js代码,你丫别给我传错了啊。于是喵喵就按照骨头上的需求来生成js脚本并且给汪汪一个响应“拿好你的骨头,别搞丢了” 汪汪的jsonp.html
上面实现的是编码动态查询,也是jsonp客户端实现的核心。
下面是如何完成jsonp调用的全过程。 上面url中的code参数表示dog告诉cat我要查询附近猪骨的信息,并且把一个叫callback的骨头给cat,说这是我们的暗号(boneHandler),别和其他狗子搞混了,你把结果都放到这块骨头的这个暗号中给我传过来。
于是这个叫做boneResult.aspx的页面生成了一段这样的代码提供给jsonp.html
boneHandler({
"code": "pig",
"price": 170,
"nums": 5
});
4 如何用jquery实现? Attention:jquery在处理jsonp类型的ajax时(虽然jquery也把jsonp归入了ajax,但其实它们真的不是一回事儿),自动帮你生成回调函数并把数据取出来供success属性方法来调用
1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext(?)等框架都把jsonp作为ajax的一种形式进行了封装;
2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。
3、其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变着一点!
“傻喵,听懂了么?”
参考资料:
路易斯的blog(推荐看看他的blog,内容满赞的,尤其那个关于mac上使用alfred的技巧,很清晰)
阮一峰的日志
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1eteae3c4sdc0