请选择 进入手机版 | 继续访问电脑版

前端跨域的七种解决方案

[复制链接]
毕高严 发表于 2020-12-31 20:25:11 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
前端开发的汗青年轮


  • 服务端渲染
  • 客户端渲染(同源计谋)
  • 客户端渲染(跨域方案)
  • 半服务端渲染(SSR)
谈谈你对跨域的明白

跨域主要分3部门:

  • 协议相同
  • 域名相同
  • 端口相同
只要有一个差异,那么就是跨域
  1.   // 地点  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

    • 指定额外的发送头信息,以逗号分割字符串。

  1. 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服务,它作为一个中间层会帮客户端去像服务端请求数据,然后把数据返回给客户端。
  1. 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的实现
  1. 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反向署理

这是后端需要做的,实在我也不是很熟悉,大抵设置方式。
  1. 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
  1. iframe.onload = function () {  iframe.contentWindow.postMessage('消息', 'http://127.0.0.1:1002/');}//=>监听B传递的信息window.onmessage = function (ev) {  console.log(ev.data);}
复制代码
B.html
  1. 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域名页面
  1. 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域名页面
  1. 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域名页面
  1. 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域名页面
  1. 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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )