Hello小可爱们~~我又来了,还记得昨天说的今天要说什么吗???是滴,今天要说的就是跨域!
同源策略
首先呢,我们要说说,为什么会出现跨域这个东西,不管是面试还是工作总是咬着我们不放,这都源于——同源策略!
同源策略是浏览器最核心、最基本的安全功能,保证了浏览器的正常功能。同源策略要求不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。同源策略的同源指的是域名、协议、端口都相同,如果不是同源的脚本,那么浏览器会在控制台报错,拒绝访问。但是我们可以通过img 的src引用远程图片,通过script标签的src加载远程js,这种情况是不受同源策略影响的,可以视为本地资源,即视为同源。
虽然我们都很讨厌它的存在,那么没有它行不行呢?当然不行!那会造成你所访问的网站极其不安全,更容易受到CSRF、XSS攻击或被迷惑引导进入钓鱼网站。
那么怎样让浏览器不放弃同源策略的保护的情况下,又能够优雅的运行跨域脚本呢~
1
JSONP
JSONP利用<script>标签实现跨域访问,这是一种非常简单的跨域解决方法,但是只能应用GET方法,而且可能被注入恶意代码。
1) 动态插入script标签
2)向服务器请求json数据
3)返回的数据将在回调函数中获取
function addScript(src){
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.src = src;
document.body.appendChild(script);
}
//回调函数
function rabbit(data){
console.log('Your rabbit's name is:'+data.name)//所以这里data能够或得到数据
};
window.onload = function(){
addScript('http://mengtuit.com/name?callback=rabbit')//后端将方法放在参数中
}
2
CORS
W3C标准的跨域资源共享。这主要依赖于后端代码,添加Access-Control-Allow-Origin,如果使用了Spring-boot能够更简单的通过注解@crossDomain实现
// 处理成功失败返回格式的工具
class CrossDomain {
static async cors (ctx) {
const query = ctx.request.query
// 如果需要http请求中带上cookie,需要前后端都设置credentials,且后端设置指定的origin
ctx.set('Access-Control-Allow-Origin', 'http://localhost:9099')
ctx.set('Access-Control-Allow-Credentials', true)
// 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)
// 这种情况下除了设置origin,还需要设置Access-Control-Request-Method以及Access-Control-Request-Headers
ctx.set('Access-Control-Request-Method', 'PUT,POST,GET,DELETE,OPTIONS')
ctx.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, t')
ctx.cookies.set('tokenId', '2')
ctx.body = successBody({msg: query.msg}, 'success')
}
}
3
window
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
4
HTML5
1) postMessage:otherWindow.postMessage(message, targetOrigin, [transfer]);
允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
2)websocket:HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。
<script>
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('兔兔那么可爱,怎么能吃兔兔!');//向服务器发送数据
}
socket.onmessage = function (e) {
console.log(e.data);//接收服务器返回的数据
}
</script>
5
Nginx
搭建中转nginx服务器,用于转发请求,通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
1. 修改nginx目录下的nginx.conf:
// proxy服务器
server {
listen 80;
server_name www.rabbit1.com;
location / {
proxy_pass http://www.rabbit2.com:8080; #反向代理
proxy_cookie_domain www.rabbit2.com www.rabbit1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.rabbit1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
2. 启动nginx:nginx -s reload
// index.html
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.rabbit1.com:81/?user=admin', true);
xhr.send();
// server.js
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var params = qs.parse(req.url.substring(2));
// 向前台写cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.rabbit2.com;HttpOnly' // HttpOnly:脚本无法读取
});
res.write(JSON.stringify(params));
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
解决跨域的淫奇技巧就先写在这吧,不知道别人,反正我觉得在工作中用到的最多的就是nginx和CORS的方法,其他方法或者不稳定或者有局限性,不过这些也是见仁见智啦~~喜欢兔妞的文章请关注并点击好看让更多人看到哦!如果能打个赏就更加感激不尽了!!!么么哒!!!
最后送大家一道题,看看大家知不知道那些是同源的呢?
1. http://www.a.com/a.js
http://www.a.com/b.js
2. http://www.a.com/a/a.js
http://www.a.com/b/b.js
3. http://www.a.com:8000/a.js
http://www.a.com/b.js
4. http://www.a.com/a.js
https://www.a.com/b.js
5. http://www.a.com/a.js
http://192.168.82.45/b.js
6. http://www.a.com/a.js
http://child.a.com/b.js
7. http://www.a.com/a.js
http://a.com/b.js
8. http://www.a.com/a.js
http://www.b.com/b.js