本文是在阮一峰老师和方应杭老师的教程上总结写得,相关链接:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
首先,同源是什么?
网站url由 协议 + 域名 + 端口 + 路径组成,也可能包含查询参数和锚点
image.png
只要两个网址协议域名端口有一个不一样,这两个网址就是非同源
image.png
为何会有同源政策
目的就是保证安全,假如用户访问了网页A,然后又去访问网页B,要是网页B能读取到A的cookie(比如登录信息等......),那互联网就没有安全可言了。
同源策略对非同源网页作出了限制:
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
那面对非同源url,如何实现跨域?
可以选择JSONP来进行跨域请求。
先来了解一下JSONP:
我们知道,script标签是不受跨域限制的。比如用script请求cdn资源,就从来没有受过限制,于是就有脑洞大开的程序员想到,可以动态生成一个script标签做跨域了!
只要我传一个回调函数给后端,后端给我返回函数的调用,那我这个script标签在html中总会执行的吧,那不就可以了吗?
来看代码:
let script = document.createElement('script')
window[functionName] = function () {
console.log('要执行的回调函数');
}
script.src = 'http://xxx.com?callback=' + functionName
document.body.appendChild(script) // script必须插入页面中才会执行
// 这里省略了后台代码,只需要知道后台会返回一个functionName(),这个functionName()会被放入script中执行就可以了
// 这里我们就已经实现了简单的JSONP了。
我们再来完善一下,将传入参数统一规定为callback,callback的值统一为随机数(为了防止重复,毕竟一个服务器可能要处理成千上万个请求)
let functionName = Math.random()*10000;
let script = document.createElement('script')
window[functionName] = function () {
console.log('要执行的回调函数');
}
script.src = 'http://xxx.com?callback=' + functionName
document.body.appendChild(script)
再来看看,现在我们的JSONP已经写的还行了,但是有一个问题,我每做一次JSONP请求,页面就会被嵌入一个标签,而且全局会出现一个随机数的函数,这些前端肯定不能忍啊,必须干掉! 那我们就在script执行完之后干掉吧,用script.onload
let functionName = Math.random()*10000;
let script = document.createElement('script')
window[functionName] = function () {
console.log('要执行的回调函数');
}
script.src = 'http://xxx.com?callback=' + functionName
document.body.appendChild(script)
script.onload = function(e){
e.currentTarget.remove() // 干掉嵌入的script标签
delete window[functionName] // 删掉定义的回调函数
}
完美,接下来,我们只要写一写请求失败的情况就可以了
let functionName = Math.random()*10000;
let script = document.createElement('script')
window[functionName] = function () {
console.log('要执行的回调函数');
}
script.src = 'http://xxx.com?callback=' + functionName
document.body.appendChild(script)
script.onload = function(e){
e.currentTarget.remove() // 干掉嵌入的script标签
delete window[functionName] // 删掉定义的回调函数
}
script.onerror = function (e) {
e.currentTarget.remove() // 失败了也要删除script标签
delete window[functionName] // 失败了也要干掉这个随机函数
}
完。
网友评论