跨域请求之JSONP

前言

由于安全原因,浏览器会限制脚本发起跨站请求,是为浏览器的同源策略。而有时我们又需要跨站请求,比如一个大型网站多个域名之间的信息协同共享。在不违反同源策略的前提下,大概有CORS,JSONP,Proxy Server等技术达到跨站请求的目的。前面我介绍了CORS,它是W3C推荐跨站请求方式,也更安全。这篇文章主要介绍JSONP。

什么是JSONP

JSONP全称(JSON with Padding),是一种基于html中<script>标签实现跨域请求的技术。

为了方便全文举例说明,某页面所在的网站假设为www.foo.com,请求跨站至www.bar.com获取数据。

浏览器同源策略虽然限制了跨站AJAX请求,但通过<script>标签加载跨站脚本是所有浏览器都支持的。所以当需要通过跨站请求获取数据时,可以通过嵌入<script>标签来实现跨站请求。比如在网站foo的页面上,跨站请求网站bar,获取id为23的用户信息,以JSON格式返回。如图:

以上跨站请求能成功发送到bar站,并返回JSON数据,但通过<script>请求加载的用户信息并没有被赋值到具体的变量上,这使得当前页面的javascript并不能操作这个结果,且浏览器解析会报语法错误。为了解决这个问题,网站bar在返回的JSON结果外包一个方法名(这即称之为Pading),而这个方法名对应的方法在foo站页面是事先存在的。这使得返回的Pading结果被浏览器当作一句方法调用脚本执行。从而回调方法可以获取JSON数据进行相关的业务操作。这即为JSONP的原理和实现。交互图如下:

值得一提的是,代码逻辑在需要跨站请求时,通过原生javascript在当前页注入<script>标签较为繁琐,jQuery提供了更好的封装,使得一个JSONP调用写起来跟普通AJAX类似。

缺陷

通过<script>标签的方式实现跨站请求,看起来有点像小trick。请求双方并没有任何限制和安全检查,比如黑白名单设计。这使得JSONP存在着以下风险。

对于提供JSONP服务器的bar站来说,如果该JSONP请求返回的是敏感数据,那么恶意脚本也可以请求获取到。恶意脚本还可以不停的请求该服务,占用资源,致使正常访问无法进行。

同时由于请求是通过<script>标签发起,故请求的方法也只能是GET,而不能用POST等其他方式,不利于大量数据的提交。

后话

JSONP的兼容性较好,对浏览器没有什么特殊要求,现役的浏览器基本都能支持。但在安全性方面并不可控,显得有些粗粒度。所以CORS是更值得推荐的跨站请求方案。

参考资料

https://en.wikipedia.org/wiki/JSONP