一、同源策略
1、源
- 源=协议+域名+端口号
2、同源
- 如果两个url,协议、域名、端口号完全一致,即为同源
- 如,qq.com 和 www.baidu.com 不同源
- 如,baidu.com 和 www.baidu.com 不同源
3、同源策略
- 浏览器规定:若JS运行在源A里,那么就只能获取源A的数据,不能获取源B的,即不允许跨域
- 举例:frank.com/index.html 引用了 cdn.com/1.js ,即1.js运行在frank.com里,与cdn.com无关,只是1.js从cdn.com处下载,所以,1.js只能获取frank.com的数据
- 为什么要有同源策略:保护用户隐私。总而言之,不同源的页面之间,不准互相访问数据
4、实操理解跨域
需提前自己做两个网站来模拟正常网页(qq.com)和黑客网页(lanlan.com)
- 在qq.com:8888里运行的JS可以访问/friends.json(正常使用AJAX)
- 在lanlan.com:9999里运行的JS不可以访问(黑客偷数据)
- 黑客的请求成功发送,但未成功拿到响应
5、一些答疑
- a.qq.com访问qq.com也算跨域?why
- 历史上,出现过不同公司公用域名,a.qq.com和qq.com不一定是同一个公司
- 不同端口也算跨域?why
- 同上,不同端口不一定是同一个公司
- 两个网站IP一样也是跨域?why
- 同上,IP可以不同公司共用
- 那为什么可以跨域使用如CSS、JS、图片等
- 同源策略限制的是数据访问,引用CSS、JS、图片时,并不知道其具体内容,只是引用
二、如何跨域
1、CORS
Crose-Origin Resource Sharing,跨源资源共享
- 如果要共享数据,需提前申明
- 在对应的响应头里写lanlan.com可以访问
response.setHeader("Access-Control-Allow-Origin","http://lanlan.com:9999")
2、JSONP
- IE6 7 8 9不支持CORS,要兼容IE,可以使用JSONP
- 理解JSONP:我们可以引用JS,那么就让JS包含JSON的数据即可,可以理解为P是包含之意
- 但不一定非得是JSON,也可以是XML等,只是命名为JSONP而已(注意:JSON和JSONP完全不相干)
2.1、操作步骤
- 新建friends.js,将JSON数据写进该JS里
else if(path==="/friends.js"){
const string=fs.readFileSync("./public/friends.js").toString(); //拿到JS内容
const data=fs.readFileSync("./public/friends.json").toString(); //拿到JSON数据
const string2=string.replace("{{data}}",data); //将数据填入JS内容里
}
- lanlan.com用script标签引用/friends.js
const script=document.createElement('script')
script.src='http://qq.com:8888/friends.js'
document.body.appendChild(script)
script.onload=()=>{
script.remove() //为防止script堆积,用完即删
}
- friends.js执行lanlan.com事先定义好的window.xxx函数(回调)
window.xxx=(data)=>{
console.log(data)
}
window.xxx=({{data}}) //lanlan.com就通过window.xxx获取到了数据
2.1.1、优化
- JSONP如何做到定向分享(即只有lanlan.com能访问qq.com,lanlan2.com不能)。加个判断
else if(path==="/friends.js"){
if(request.headers["referer"].indexOf("http://lanlan.com:9999")===0){
...
}else{
response.statusCode=404
response.end()
}
}
- xxx可以不写死吗?因为有时xxx会被占用。可以,只要lanlan.com定义的函数名和qq.com/friends.js 执行的函数名是同一个即可,如可用随机数做函数名
const random='lanlanJSONPCallbackName'+Math.random()
window[random]=(data)=>{
console.log(data)
}
...
script.src=`http://qq.com:8888/friends.js?callback=${random}`
//在qq.com的server.js里将该随机函数名也填入string2里
2.2、封装JSONP
2.3、关于JSONP
- JSONP是什么?
- 在跨域时,由于当前浏览器不支持CORS,此时需要另一种方式来跨域;即请求一个JS文件,该文件会执行一个回调,回调里就有我们要的数据
- 该回调的名字是?
- 名字是可以随机生成的(用随机数),把这个名字以callback参数传给后台,后台会返回给我们并执行
- JSONP的优点是?
- 能兼容IE,可以跨域
- JSONP的缺点是?
- 由于它是script标签,读不到如AJAX那样精确的状态(如状态码),只知道是成功还是失败
- script只能发get请求(即JSONP不支持post)