前端开发的汗青年轮
- 服务端渲染
- 客户端渲染(同源计谋)
- 客户端渲染(跨域方案)
- 半服务端渲染(SSR)
谈谈你对跨域的明白
跨域主要分3部门:
只要有一个差异,那么就是跨域
- // 地点 http://www.baidu.com 协议:http:// 域名:www.baidu.com 端口:8080(http) 443(https) 默认端口省略 http://www.baidu.com/login.html // 同源 http://www.baidu2.com/login.html // 差异源,域名差异 http://www.baidu.com:81/login.html // 差异源,端口差异
复制代码 同源的目标
目标是为了掩护用户信息的安全,防止恶意网站窃取数据,否则Cookie可以共享。有的网站一般会把一些重要信息存放在cookie或者LocalStorage中,这时如果别的网站可以大概获取获取到这个数据,可想而知,这样就没有什么安全可言了。
限制范围
- Cookie、LocalStorage和IndexDB 无法读取
- DOM无法得到
- AJAX 请求不能发送
主要这3种方式不可。
管理方案
方案1:CORS
比力常见的就是nodejs设置CORS允许跨域。
- Access-Control-Allow-Origin
- 字段必传,为*表示允许任意域名的请求。当有cookie需要传递时,需要指定域名。
- Access-Control-Allow-Credentials
- 字段可选,默认为false,表示是否允许发送cookie。若允许,通知欣赏器也要开启cookie值的传递。
- Access-Control-Expose-Headers
- 字段可选。如果想要欣赏器拿到getResponesHeader()其他字段,就在这里指定。
- Access-Control-Request-Method
- 必须字段,非简朴请求时设置的字段,比方PUT请求。
- Access-Control-Request-Headers
- module.exports = { //=>WEB服务端标语 PORT: 3001, //=>CROS跨域相关信息 CROS: { ALLOW_ORIGIN: 'http://127.0.0.1:5500', ALLOW_METHODS: 'PUT,POST,GET,DELETE,OPTIONS,HEAD', HEADERS: 'Content-Type,Content-Length,Authorization, Accept,X-Requested-With', CREDENTIALS: true }};app.use((req, res, next) => { const { ALLOW_ORIGIN, CREDENTIALS, HEADERS, ALLOW_METHODS } = CONFIG.CROS; res.header("Access-Control-Allow-Origin", ALLOW_ORIGIN); res.header("Access-Control-Allow-Credentials", CREDENTIALS); res.header("Access-Control-Allow-Headers", HEADERS); res.header("Access-Control-Allow-Methods", ALLOW_METHODS); req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMAIN REQUESTS!') : next();});
复制代码 方案2:Proxy
现在主流三大框架,react,vue,argular都使用了webpack举行工程化。在当地开发最常见的就是proxy署理,管理跨域。
主要原理是:客户端像服务器请求数据。webpack-dev-server会再当地创建一个web服务,这个服务会和客户端同源。当地服务实际上是一个node服务,它作为一个中间层会帮客户端去像服务端请求数据,然后把数据返回给客户端。
- const path = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = { mode: 'production', entry: './src/main.js', output: { filename: 'main.[hash].min.js', path: path.resolve(__dirname, 'build') }, devServer: { port: '3000', compress: true, open: true, hot: true, proxy: { '/': { target: 'http://127.0.0.1:3001', changeOrigin: true } } }, // 设置WEBPACK的插件 plugins: [ new HtmlWebpackPlugin({ template: `./public/index.html`, filename: `index.html` }) ]};
复制代码 方案3:JSONP
主要原理:link,script这种是不会跨域的。所以,前端代码写一个script src = http://localhoost:80/list?callback=func,把这个链接发送给服务端。但是传递给服务端的函数必须是一个全局的函数。服务端继承到请求后,会把callback这个值,返回给客户端。客户端获取到服务端返回的指定格式字符串。发现实在就是当地的func全局函数执行,并且把数据传递给这个函数。
但是这种方式有一个毛病,那就是只能get请求,而且不安全,只要服务端支持,谁都可以调用。
下面手写一个JSONP的实现
- function jsonp(url = "", callback) { let script; // 把传递的回调函数挂载到全局上 let name = `jsonp${new Date().getTime()}`; window[name] = data => { // 从服务器获取到告终果 document.body.removeChild(script); delete window[name]; callback && callback(data); }; // 处置惩罚URL url += `${url.includes('?') ? '&' : '?'}callback=${name}`; // 发送请求 script = document.createElement('script'); script.src = url; document.body.appendChild(script);}jsonp('http://127.0.0.1:1001/list?lx=1', result => { console.log(result);});jsonp('https://matchweb.sports.qq.com/matchUnion/cateColumns?from=pc', result => { console.log(result);});
复制代码 方案4:nginx反向署理
这是后端需要做的,实在我也不是很熟悉,大抵设置方式。
- server { listen 80; server_name 192.168.161.189; #charset koi8-r; #access_log logs/host.access.log main ; location { proxy_pass http: // 192.168.161.189:8070; root html; index index.html index.html; }}
复制代码 什么是署理?
既然是署理跨域,那么署理(Proxy Server)就是一个很重要的点,这里的署理说的服务器署理,是一种很重要的服务器安全功能,也是一种很常见的设计模式,来隔绝差异的模块,解耦模块。
为什么署理是反理?
nginx就可以大概把用户的请求分发到空闲的服务器上,然后服务器返回自己的服务到负载平衡设备上,然后负载平衡的设备会讲服务器的服务返回给用户,所以我们并不知道为什么服务的是哪一台服务器发送出来的,这就很好的隐藏了服务器。有一句精炼的话是这么说的:“反向署理就是流量发散状,署理是流量汇聚状。”
方案5:POST MESSAGE
A.html
- iframe.onload = function () { iframe.contentWindow.postMessage('消息', 'http://127.0.0.1:1002/');}//=>监听B传递的信息window.onmessage = function (ev) { console.log(ev.data);}
复制代码 B.html
- window.onmessage = function (ev) { // console.log(ev.data); //=>ev.source:A ev.source.postMessage(ev.data + '@@@', '*');}
复制代码 方案6:基于iframe的跨域管理方案1——locaction.hash
原理:也是使用iframe可以在差异域中传值的特点,而location.hash正好可以携带参数,所以使用iframe作为这个差异域之间的桥梁。
A域名页面
- var iframe = document.createElement('iframe')iframe.src = 'http://www.B.com:80/hash.html'document.body.appendChild(iframe)window.onhashchange = function () { //处置惩罚hash console.log(location.hash)}
复制代码 B域名页面
- var xhr = new XMLHttpRequest()xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { var res = JSON.parse(xhr.responseText) console.log(res.msg) parent.location.href = `http://www.A.com:80/a.html#msg=${res.msg}` }}xhr.open('GET', 'http://www.B.com:80/json', true)xhr.send(null)
复制代码 缺点
- iframe虽然能管理问题,但是安全风险照旧比力重要的。
- hash传参处置惩罚起来比力贫困。
方案7:基于iframe的跨域管理方案2——window.name
原理实在是和上面的方法一样,区别在于window.name可以大概传递2MB以上的数据。
A域名页面
- var iframe = document.createElement('iframe')iframe.src = 'http://www.B.com:80/name.html'document.body.appendChild(iframe)var times = 0iframe.onload = function () { if (times === 1) { console.log(JSON.parse(iframe.contentWindow.name)) destoryFrame() } else if (times === 0) { times = 1 }}// 获取数据以后销毁这个iframe,释放内存;function destoryFrame() { document.body.removeChild(iframe);}
复制代码 B域名页面
- var xhr = new XMLHttpRequest()xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { window.name = xhr.responseText location.href = 'http://www.A.com:80/a.html' }}xhr.open('GET', 'http://www.B.com:80/json', true)xhr.send(null)
复制代码 等等其他处置惩罚方式
来源:https://blog.csdn.net/uperficialyu/article/details/111938856
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |