前端跨域你还不懂 [常见解决方案]

419 阅读4分钟

前言

跨域可以说在前端是一个非常常见的问题,遇到的场景也是各式各样,我们今天就来看看跨域到底是个什么玩意儿 . 又如何把这个玩意儿搞明白

什么是跨域

通俗一点来讲跨域是指一个域下的文档或脚本试图去请求另外一个域下的资源,这样就产生了跨域,

域: 是指计算机网络中的一种形式, 在域中使用计算机的每个人都会收到一个唯一的用户帐户,然后可以为该帐户分配对该域内资源的访问权限。

常见跨域场景

做为一个前端,我们最常遇到的跨域应该就是浏览器请求资源跨域,专业一点来讲就是受到了浏览器同源策略的限制; 所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个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 代理等等。也是一种解决方案 。