什么是同源策略
同源策略是浏览器对域名之间资源的一种限制方式,这是浏览器所设计的功能(浏览器故意这样做的),为的就是保护用户的隐私,防止用户的数据泄漏。
那么怎样的域名算不同源
baidu.com 和 qq.com
baidu.com 和 www.baidu.com
localhost:8888 和localhost:9999
上面的域名都是不同源的。只要你的域名有一点点不一样都是无法访问的,甚至端口号不同都属于不同源。
实验1 浏览器的同源策略
在本地开启了两个服务器,假设一个是qq.com,一个是黑客的ying.com,其ip地址都是本地的127.0.0.1只是端口号不同。接着ying.com试图访问qq.com源中的friends.json数据文件。
下面是qq.com自己访问friends.json的效果
成功获取到数据并渲染、
下面是黑客ying.com访问qq.com 中的friends.json的效果
报错表示地址之间不同源
**问:**为什么可以跨域使用css,js和图片资源
同源策略限制的是数据的访问,我们引用css、js、图片的时候其实并不知道其内容是什么,我们只是在引用。
如何实现跨域
如果说两个网站都是我的,有没有什么方法能够实现数据共享。
解决方案一 CORS
通过在资源的Response Header上添加Access-Control-Allow-Origin: <允许访问的域名>。就可以实现跨域名资源共享
实验2 使用CORS实现跨域
在服务器qq.com的服务器中设置qq.js文件的响应头
//允许来自 http://ying.com:9999 源的访问
response.setHeader('access-control-allow-origin', 'http://ying.com:9999');
在ying.com中成功获取到了qq.com中的json数据
CORS 在IE 6 7 8 9 中都不兼容
解决方案二 JSONP
为了兼容性IE又出现了JSONP这种技术,JSONP与JSON之间没有关系,只不过一般传输的都是json的数据类型。
基本思想就是利用浏览器没有限制CDN的引用。可以通过将数据方到js文件中然后将script脚本引入网页再适当的处理一下就可以得到其他网站的数据了。这需要资源方提供专门写一个js文件。
实验3 使用JSONP实现跨域
为了兼容IE没有办法使用CORS来实现跨域,为了实现资源共享pp.com提供了一个包含JSON数据的friends.js文件。接着ying.com使用script标签将pp.com的friends.js文件引入自己的网站,从而实现跨域获取数据。
服务器会将json数据插值到friends.js的
{{data}}中
//server.js
if (path === "/friends.js") {
response.statusCode = 200;
response.setHeader('Content-type', 'text/js;charset=utf-8');
let string = fs.readFileSync('public/friends.js').toString();
let json = fs.readFileSync('public/friends.json').toString();
string = string.replace('"{{data}}"', json)
response.write(string)
response.end();
}
将qq.com的friends.js引入到ying.com中,并做一些处理
ying.com中顺利获取到了qq.com中的数据
使用回调
这里的还可以不使用onload事件而换成回调
ying.js文件
//定义函数
window.friends = function(data) {
console.log('data:');
console.log(data);
render(data);
}
qq.com文件
//调用函数
window.friends("{{data}}") //这里的插值"{{data}}"会被服务器改为json数据
JSON存在的问题
- 所有网站都可以引用这个js文件
- 全局变量的命名空间冲突(如上面例子的
window.friends) - 每次使用JSONP请求数据都需要创建一个script标签
基于这些问题下面就来逐个击破
解决方法
- 使用referer再阻止一下网站的请求。如果请求头中的referer来判断是否是要给该网站数据
- 使用随机数加前缀
- 每次用完删除script标签,这样子是不会影响数据获取的
封装JSONP
//prve 为前缀
function jsonp(url, prve) {
return new Promise((resolve, reject) => {
const random = prve + Math.random();
window[random] = function(data) {
resolve(data);
}
const script = document.createElement('script');
script.src = `${url}?callback=${random}`
script.onload = () => {
script.remove();
}
script.onerror = () => {
reject();
}
document.head.appendChild(script);
})
}
JSONP的优缺点
优点
- JSONP可以做到不是当前的域名而是其他的域名也可以成功的跨域
- JSONP可以兼容IE,或在某种无法使用CORS的情况下成功的跨域
缺点
- JSONP 是script标签不能先ajax一样获取到数据返回的状态
- 有由于它是script标签所有只能发get请求,也就是说JSONP不支持POST
总结
只有在CORS不支持的情况下才会去使用JSONP 实验代码