jsonp在前端领域是个很常用的技术,面试中也可能会让你手写jsonp。相信很多同学都听过jsonp但对其实现原理并不是很清楚,今天咱们来一边手写jsonp一边介绍其原理。
首先为什么会有jsonp这个技术呢?都是同源策略惹的祸。那什么又是同源策略呢?所谓同源是指,域名,协议,端口相同。举个简单的栗子,你在百度的站点通过ajax是访问不到新浪的页面的?那怎么解决这个问题呢,jsonp要闪亮登场了!
什么是jsonp
ajax请求受同源策略限制不能进行跨域请求,但是script标签中的src属性却不受限制,jsonp就是利用这一特性来实现跨域请求。
手写jsonp
为了对比和ajax请求的区别我们先贴一段在本地用ajax请求百度站点数据的实例(这是个错误的实例 ,ajax不能跨域请求):
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript">
function handleRes(data){
console.log(data);
}
$(document).ready(function(){
$.ajax({
type : "get",
url : "http://www.baidu.com/person.js?id=1",
type: "json",
success : function(data) {
handleRes(data);
}
});
}); // 会报错 ajax不能实现跨域请求
</script>
利用jsonp实现跨域请求
<script type="text/javascript">
function handleRes(data){
console.log(data.name + 'is' + data.age + 'years old');
//tom is 20 years old
}
</script>
<script type="text/javascript" src="http://www.baidu.com/person.js"></script>
假使我们访问的url http://www.baidu.com/person.js 的代码如下
handleRes({name: 'tom', age: 20})
这段代码什么意思呢? 访问的远程服务上返回一个方法的执行也就是 handleRes({name: ‘tom’, age: 20}) 而恰巧本地定义了一个方法也叫handleRes。这难道是巧合么?当然不是。我们需要在url后添加一个参数来约定这种关系。所以完整的写法应该是这样的:
<script type="text/javascript">
function handleRes(data){
console.log(data.name + 'is' + data.age + 'years old');
}
</script>
<script type="text/javascript" src="http://www.baidu.com/person.js?callback=handleRes"></script>
//这个callback本身也是可配置的。
这里介绍两种封装jsonp的方法:
1、利用jQuery发送jsonp请求
$.ajax({
url: 'xxxxx', //一个跨域的url
type: 'get',
dataType: 'jsonp', //设置服务器返回的数据类型
jsonp: 'onJsonPLoad', //这个值用来配置前面提过的callback,它会拼接到url的后面
jsonpCallback: 'handleRes', //用来设置回调函数名称
success: function (res){ //这里的success回调就相当于之前写到的handleRes方法。
console.log(res);
}
})
2、可能很多小伙伴都不在项目中使用jQuery了,我们可以利用这个 https://github.com/webmodules/jsonp 插件来封装一个发送jsonp请求的方法,这个插件的具体使用方法也很简单大家可以点开链接查看,这里就不做赘述了。
import originJSONP from 'jsonp'
export default function jsonp(url, opts) {
return new Promise((resolve, reject) => {
originJSONP(url, opts, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
使用的时候也很简单
import jsonp from 'xxx'
jsonp('http://xxx', {param: 'jsonpCallback'}).then((res) => {
....
})