前言
跨域可以说在前端是一个非常常见的问题,遇到的场景也是各式各样,我们今天就来看看跨域到底是个什么玩意儿 . 又如何把这个玩意儿搞明白
什么是跨域
通俗一点来讲跨域是指一个域下的文档或脚本试图去请求另外一个域下的资源,这样就产生了跨域,
域:
是指计算机网络中的一种形式, 在域中使用计算机的每个人都会收到一个唯一的用户帐户,然后可以为该帐户分配对该域内资源的访问权限。
常见跨域场景
做为一个前端,我们最常遇到的跨域应该就是浏览器请求资源跨域,专业一点来讲就是受到了浏览器同源策略的限制; 所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
协议:http/https 域名www.HiSen.com 端口:8080
URL 说明 是否允许通信
http://www.HiSen.com
http://www.HiSen.com 同一域名 允许
http://www.HiSen.com:8080
http://www.HiSen.com:8081 同一域名,不同端口 不允许
http://www.HiSen.com
https://www.HiSen.com 同一域名,不同协议 不允许
http://www.HiSen.com
http://192.168.1.37 域名和域名对应相同ip 不允许
http://www.HiSen1.com
http://www.HiSen2.com 不同域名 不允许
如何解决
Jsonp
说到 jsonp
可能大家都在吐槽,比较土,就目前的主流框架 vue react
来讲可能都很少使用 ajax
来进行网络请求,在这里呢,我们也做一个简单分享,在我的理解中 ,jsonp
其实就是前端定义一个全局的回调函数来被服务端执行,回调函数的参数就是请求返回值;我们通过代码来认识一下:
前端通过请求一份数据,通过一个 get
请求来简单实践一下。
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.HiSen.com:8080/getData?callback=callbackFun';
document.head.appendChild(script);
// 定义全局回调函数
function callbackFun(res) {
alert(JSON.stringify(res));
}
</script>
后端我们通过一个简单的 node
服务来看一下。
var http = require('http');
var url = require('url');
var server = http.createServer();
server.on('request', function(req, res) {
//获取get请求参数
var params = qs.parse(req.url.split('?')[1]);
//获取callback函数名称
var fn = params.callback;
// jsonp返回设置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
// 返回一个全局函数被执行 - 也就是页面上定义的全局回调函数
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
通过上边的这个实例,大家是否都明白了呢 ? 其实就是通过服务端返回一个全局执行回调函数,参数就是我们要返回的值。当然这是通过原生Js来诠释的,其它的大家也不用担心,都是有处理过的;
ajax
只需要设置 dataType:jsonp
,并设置 jsonpCallback:回调函数名称
即可,
vue
也有对应的设置 jsonp: 回调函数名称
缺点就不言而喻了,JSONP
只能 GET
请求 .
cors
跨域资源共享,这个也许是小伙伴们使用最多的解决方案了,平时的工作中也都是通过服务端来设置 Access-Control-Allow-Origin
即可,简单,快捷;CORS也已经成为主流的跨域解决方案。
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,若要带cookie请求:前后端都需要设置。
关于 vue
框架,大家目前使用较多的就是 axios 和 vue-resource
了, 那么它们两个呢都需要简单设置一下:
//axios设置:
axios.defaults.withCredentials = true
//vue-resource设置:
Vue.http.options.credentials = true
服务端请自行查阅一下如何设置 Access-Control-Allow-Origin
属性,这里我就不拿 node
做样例了。
node中间件代理
其实说到node
中间件,就是启动一个代理服务器,做数据转发,变相的 cros
跨域资源共享 , 在 node
那里去设置一些返回头属性 Access-Control-Allow-Origin
拿 express
框架来说:
var express = require('express');
var app = express();
app.all("*",function(req,res,next){
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin","*");
//允许的header类型
res.header("Access-Control-Allow-Headers","content-type");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
next();
}
WebSockt 协议
web sockets是一种浏览器的API,长连接双向通信。(同源策略对web sockets不适用)
web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会把http协议替换为web sockt协议。
var socket = new WebSockt('ws://www.HiSen.com');//http -> ws; https -> wss
socket.send('WebSockt 连接');
socket.onmessage = function(event){
var data = event.data; // 回调
}
当然了,还有一些同学可能会说到目前的 webpack
有各种配置 ,例如 vue 就有 proxy
代理等等。也是一种解决方案 。