文章目录
查看github源码
代码使用方法
-
安装 node-dev
yarn global add node-dev
-
下载代码
https://github.com/FrankFang/kuayu-1.git
-
进入 qq-com 运行 server.js
cd kuayu-1/qq-com; node-dev server.js 8888
-
进入 frank-com 运行 server.js
cd ../frank-com; node-dev server.js 9999
-
设置 hosts
127.0.0.1 qq.com 127.0.0.1 frank.com
-
打开两个页面 qq.com:8888/index.html 和 frank.com:9999/index.html
-
记得做完之后,删掉 hosts 里的两行,否则 qq.com 无法正常访问!
同源策略
源:控制台得当前源,由协议+域名+端口号
window.origin
"https://www.baidu.com"
location.origin
"https://www.baidu.com"
同源:协议、域名、端口号完全一致,如"https://www.baidu.com"与"https://baidu.com"不同源
同源策略:为了保护用户隐私,不同源的页面之间,不准互相访问数据
浏览器规定:如果js运行在源A里,便只能访问源A里的数据,不允许跨域访问
举例子:js下载的源和js运行的源不同
frank.com/index中引用了cdn.com/1.js,则1.js是运行在frank中,源为frank.com,与下载的地方无关
举例子:无同源策略会如何?为什么要这设置?
当用户已登录时,可通过Ajax来获取用户列表,但是钓鱼网站也可以获取,由于无法区分发送者且后端不检查,虽referrer存在区别,所以浏览器加上同源策略来提高用户隐私安全性。
创建两个server
qq-com和frank-com
1.分别对两个加监听,用server.js,监听不同端口node server.js 9999和node server.js 8888
2.修改内容并实现自动监听:
新建终端1:yarn global add node-dev,再node-dev server.js 8888
新建终端2:node-dev server.js 8890
3.在qq.com中设置public中放首页index.html
fs.readFileSync(’./public/index.html’)
if (path === "/index.html") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.write(fs.readFileSync('./public/index.html'));
response.end();
}
4.加入qq.js和friends.json(双引号),设置好contentType
[{
"name": "喻峰"
}, {
"age": 18
}]
5.给frank设置public中加index.html和frank.js
//server.js部分代码
if (path === "/index.html") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.write(fs.readFileSync('./public/index.html'));
response.end();
} else if (path === "/frank.js") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
response.write(fs.readFileSync('./public/frank.js'));
response.end();
}
修改hosts
以管理员身份打开,所有文件
hosts位置:C:\Windows\System32\drivers\etc
设置本地域名映射:
在etc内部后面加上
qq.com 127.0.0.1,便可以访问http://qq.com:8888/index.html
frank.com 127.0.0.1,便可以访问http://qq.com:8890/index.html
直接可qq.com:8888/index.html
演示跨域被阻止 跨域AJAX
1.正常使用AJAX,可以访问/friend.json
- ‘GET’, ‘./friends.json’
- request.readyState === 4
- request.status === 200
//index页面先引用qq.js
//qq.js代码实现ajax
const request = new XMLHttpRequest()
request.open('GET', './friends.json')
request.onreadystatechange = () => {
if (request.readyState === 4 && request.status === 200) {
console.log(request.response)
}
}
request.send()
2.黑客偷数据,运行js不能访问,刷新黑客页面,终端也在增加请求
浏览器需要CORS,黑客请求发成功了,拿不到响应,跨域时浏览器不给他
知识点:路径的设置http://qq.com:8888/friends.json
const request = new XMLHttpRequest()
request.open('GET', 'http://qq.com:8888/friends.json')
request.onreadystatechange = () => {
if (request.readyState === 4 && request.status === 200) {
console.log(request.response)
}
}
request.send()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j4buAvvQ-1591253655022)(https://s1.ax1x.com/2020/06/03/twAlPf.png)]
安全链条的强度取决于最弱一环,任何安全问题都要严格对待
1.为什么a.qq.com访问qq.com算跨域?
不同公司可能共用域名
2.为什么不同端口也算跨域?
不同公司共用服务器
3.为什么两公司ip一样,也算跨域?
ip可以公用
4.为什么可以跨域使用css、js和图片?
同源策略限制的是数据访问,由于只是引用,但是不清楚其内容,不可通过ajax跨域访问到
实现跨域
方法一:CORS
Cross-origin resource sharing
共享数据前,要对后台数据方的响应头,进行声明,允许某不同源网站访问
response.setHeader(‘Access-Control-Allow-Origin’, ‘http://frank.com:8890’)
//允许的网址为协议+域名+端口号完全相同
else if (path === "/friends.json") {
response.statusCode = 200;
response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8890')
response.setHeader("Content-Type", "text/json;charset=utf-8");
response.write(fs.readFileSync('./public/friends.json'));
response.end();
}
允许多个网站访问: console.log(request.headers['referer'])
request.headers['referer']
是对应http://frank.com:8890/index.html,把http://frank.com:8890放在响应头里
方法二:JSONP
兼容IE6\7\8\9,把数据写在JS文件中,在qq.com加入文件:server.js
//friends.js 关闭自动格式化
//变量版本friends.js
window.xxx = {{data}}
//函数版本friends.js
window.xxx( {{data}} )
//server.js代码
else if (path === "/friends.js") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
const string = fs.readFileSync("./public/friends.js").toString();
const data = fs.readFileSync("./public/friends.json");
const string2 = string.replace('{{data}}', data);
response.write(string2);
response.end();
}
//引入其他源网页的js的数据:在frank.js中新建script标签,链接到qq.com下的friends.js,再将script标签加到body体中
//变量版本frank.js
const script=document.createElement('script')
script.src="http://qq.com:8888/friends.js"
script.onload=()=>{
console.log(window.xxx)
} //下载成功,拿到数据
document.body.appendChild(script)
//函数版本frank.js
window.xxx=(data)=>{
console.log(data)
}
const script=document.createElement('script')
script.src="http://qq.com:8888/friends.js"
document.body.appendChild(script)
关键点:
const string = fs.readFileSync("./public/friends.js").toString(); //获取{{data}}
const data = fs.readFileSync("./public/friends.json"); //获取JSON中的数据
const string2 = string.replace(’{{data}}’, data); //把json中数据替换到js中
此时查看控制台和window.xxx数据
总结JSONP思路
需求:frank.com访问qq.com中的朋友列表
实现:
- 把qq.com的数据放在/friends.js,非真数据是占位
- frank.com用script动态标签引用/friends.js
- /friends.js执行,执行什么
- 执行frank.com事先定义好的window.xxx函数,即回调函数
- /friends.js执行window.xxx({{data}})
- 然后通过frank.com就通过window.xxx获得数据
JSONP通过referer来指定网站访问
关键:判断referer的前三段是否一致
if(request.headers[‘referer’].indexOf(“http://frank.com:8890”)===0)
else if (path === "/friends.js") { if(request.headers['referer'].indexOf("http://frank.com:8890")===0){
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
const string = fs.readFileSync("./public/friends.js").toString();
const data = fs.readFileSync("./public/friends.json");
const string2 = string.replace('{{data}}', data);
response.write(string2);
response.end();
}else{
response.statusCode=404;
response.end();
}
}
优化JSONP,用functionName
关键点:
- 生成随机数:
?functionName=${random}
及都用下引号包住 - 替换window函数的xxx:
.replace('{{xxx}}',query.functionName);
- 数字用引号包住 window[’{{xxx}}’]
//frank.js中
const random=Math.random()
window[random]=(data)=>{
console.log(data)
}
const script=document.createElement('script')
script.src=`http://qq.com:8888/friends.js?functionName=${random}`
document.body.appendChild(script)
//qq.com中的server.js
const string2=string.replace('{{data}}',data).replace('{{xxx}}',query.functionName);
//friends.js的代码
window['{{xxx}}']( {{data}} )
script标签创建、链接、执行、删除
script.onload=()=>{
script.remove()
}
封装JSONP
//封装一下JSONP
function jsonp(url) {
return new Promise((resolve, reject) => {
const random = Math.random()
window[random] = (data) => {
resolve(data)
};
const script = document.createElement('script')
script.src = `${url}?callback=${random}`
script.onload = () => {
script.remove()
}
script.onerror = () => {
reject();
}
document.body.appendChild(script)
})
}
jsonp("http://qq.com:8888/friends.js").then((data)=>{console.log(data)})
知识点:
-
functionName改成callback
-
friends.js是没有必要的 const string = fs.readFileSync("./public/friends.js").toString();改成const string =`window[’{{xxx}}’]({{data}})`
-
script.onerror = () => {reject();}的添加
JSONP是什么?
在跨域时,浏览器或者条件不支持CORS,我们必须以另一种方式实现跨域
在本网站创建个script标签,来请求其他网站的js文件,js文件会执行一个回调,回调里有我们需要的数据
命名:是生成随机数,再把这个名字以callback的参数传给后台,后台会将函数返给我们并执行
优点:兼容ie和实现跨域
缺点:由于是script标签引用
1.没有ajax那样能看待请求头和状态码
2.不能发送post请求