jsonp的原理和使用

浏览器的同源策略不允许跨域,jsonp是解决跨域的一种方法。但也存在一些缺点,所以跨域最好还是后台进行设置.

原理

  • 利用script标签的src属性不受同源策略影响(协议,端口,域名任何一个不同,同源策略都会禁止跨域)
  • 通过前端方法作为参数传递到服务器,服务器注入参数后再返还,实现服务器向客户通信
  • 只支持get方法

请求过程

  • 请求前:创建一个script标签,并给src赋值 url+callback的方法名,并在window上注册这个方法
  • 发送请求: 将script添加到页面中,浏览器会发起一个请求
  • 数据响应:服务器将返回的数据作为参数和函数名拼接在一起 jsonpCbk({data:”data”})。当浏览器接收到响应数据,由于发起请求的是script,所以相当于直接调用jsonpCbk方法,并且给回调传入了一个参数。

原生js写一个jsonp

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
// url要请求的地址以及拼接的参数;opts{param: 约定的函数参数,timeout:超时时间,name:指定的函数名,prefix:指定的函数名前缀};fn回调函数
var count = 0
function noop(){}
function jsonp(url, opts, fn) {
// opts 如果是一个函数 赋值给fn 并重置opts为空对象
if('function' == typeof opts){
fn = opts
opts = {}
}
// 如果没有opts 给opts赋值空对象
if(!opts) opts = {}
var prefix = opts.prefix || '__jp'
// id为opts的name或者prefix+计数(prefix为opts.prefix或__jp)
var id = opts.name || (prefix + (count++))
var param = opts.param || 'callback'
// 有opts.timeout 就取 没有就是60000ms
var timeout = null != opts.timeout ? opts.timeout : 60000
var enc = encodeURIComponent
// 第一个script或者head标签
var target = document.getElementsByTagName('script')[0] || document.head
var script
var timer
// 如果有timeout就在timeout之后执行clean并抛出Error
if (timeout) {
timer = setTimeout(function(){
cleanup()
if(fn) fn(new Error('Timeout'))
}, timeout)
}
function cleanup() {
// 移除创建的script 回调函数置空 清除定时器
if(script.parentNode) script.parentNode.removeChild(script)
window[id] = noop
if(timer) clearTimeout(timer)
}
function cancel() {
if(window[id]) {
cleanup()
}
}
// 全局挂载id
window[id] = function(data) {
cleanup()
// 请求返回后执行回调fn
if(fn) fn(data)
}
url += (~url.indexOf('?') ? '&' : '?') + param + '=' + enc(id);
url = url.replace('?&', '?');
// 创建script标签src属性赋值url
script = document.createElement('script')
script.src = url;
// 插入到head或script的前面
target.parentNode.insertBefore(script, target);
return cancel;
}

以上是参照一个jsonp插件的源码写的 传送门

此方法在调用时需要自己拼接将参数拼接在url后面 opts如果跟后台有约定callback参数名就传{param: 约定参数名} ,没有默认callback

------ 本文结束------
0%