通俗易懂讲解跨域问题

271 阅读6分钟

引入:跨域是什么,同源策略是什么?

浏览器的同源策略 会限制不同源之间的交互,这是浏览器的一种安全机制,同源策略主要用于防止恶意网站跨域访问用户敏感数据。它限制了网页中的脚本只能与同源(协议、域名、端口相同)的资源进行交互,从而保护用户数据的安全。

这里简单说一下浏览器的同源策略能预防什么问题:

  1. 防止跨站脚本(XSS)窃取数据:
  • 用户登录 https://example.com,此时 Cookie 包含了用户的认证信息。
  • 如果用户访问一个恶意网站 https://malicious.com,恶意脚本试图通过 AJAX 获取 https://example.com 上的数据。
  • 同源策略会阻止这种跨域请求,保护用户信息不被窃取。
  1. 防止跨站请求伪造(CSRF)攻击读取数据:
  • 用户已登录 https://bank.com(银行网站)。
  • 恶意网站 https://attacker.com 诱使用户触发请求,但脚本无法读取 https://bank.com 的响应结果(如账户余额)。
  • 虽然请求发出去了,但恶意网站无法获取数据返回内容,降低了攻击的危害
  1. 防止跨域访问 DOM 对象
  • 一个 iframe 嵌入了 https://secure.com 的登录表单。
  • 如果 iframe 页面来源和父页面不同源,父页面脚本无法访问 iframe 的 DOM 内容。
  • 这可以防止恶意父页面通过脚本窃取 iframe 内输入的用户名和密码。
  1. 防止跨域读取 Cookie 和 LocalStorage
  • 恶意网站 https://malicious.com 无法读取 https://secure.com 下的 Cookie 或 LocalStorage 数据,即便用户已登录。

等等。。。。

为什么我开发时会遇到跨域问题呢?

我们本地调试一般都是 npm run serve,然后打开 本机ip:8080(localhost:8080)对吧,这时候我们要调接口调试,后端的接口的地址可能在测试环境,也可能是自己电脑的 ip,总之不是你的 lcoalhost:8080,那么你调接口就会产生跨域,那么怎么办呢?就需要proxy出场了。

proxy

首先,proxyTable是我们在本地开发环境中调试接口用的,目的是为了解决本地跨域的问题,在线上的生产环境是没用的!

本地代理是开发环境才会生效,打包为生产环境后会自动失效,打包之后会出现跨域,是因为后台接口服务没有配置响应头的跨域机制,以java为例(response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization")),当然,如果后台服务本身设计就是为了安全不开放跨域访问,那可以将打包之后的前端代码放在nginx内,并设置反向代理到对应的接口服务即可

为什么开发阶段才需要解决跨域,项目发布到生产环境就proxy的配置就无效了?

同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 一般前端项目最后都会打包到和接口地址相同的服务器上,此时同源不会出现跨域。并且,前端是无法解决真正的跨域问题的。proxy根本不能解决跨域,最终要跨域还是要后端配合。proxy只是前端在开发的时候,方便开发使用的东西而已,打包后就无效了。

vue-cli的proxyTable用的是http-proxy-middleware,它是http代理中间件,它依赖node.js,基本原理是用服务端代理解决浏览器跨域。 该中间件本质上是在本地开了一个服务器dev-server,所有的请求都通过这里转发出去,即把浏览器的发送请求代理转发到代理服务器上,再由代理服务器发送请求给目标服务器,从而解决跨域问题。

原理 vue 中的 proxy 就是利用了 Node 代理,原理还是因为服务器端没有跨域这一说嘛,也是用了这么一个插件 地址

跨域之proxyTable——在开发和生产环境的不同配置: blog.csdn.net/bonjourjw/a…

image.png

 // 如果你想看代理后的路径
        onProxyReq: function (onProxyReq, req, res) {
          console.log('原相对路径' + req.originalUrl, '代理相对路径:' + req.path)
          // 这里的输出是自己配的,就是说开发环境控制台看到的地址,proxy代理成的样子,打印:http://localhost:9528/dev-api/manage/tFmAuthPlan/query
          console.log('前端请求url', onProxyReq._headers.origin + req.originalUrl)
          // 代理配置的目标地址,打印: http://192.168.0.223:18181/ad2api/manage/tFmAuthPlan/query
          console.log(
            '目标请求url2',
            onProxyReq.agent.protocol + '//' + onProxyReq._headers.host + onProxyReq.path
          )
        }

个人理解proxyTable中跨域中pathRewrite的用法

问: proxyTable 里面的pathRewrite里面的 ,^/api 什么意思?

答: 用代理,首先你得有一个标识,告诉他你这个连接要用代理,不然的话,可能你的 html,css,js这些静态资源都跑去代理.所以我们只要接口用代理,静态文件用本地 '/api': 就是告诉node,我接口只要是 '/api' 开头的请求才用代理,所以你的接口就要这么写 /api/xx/xx,最后代理的路径就是xxx.xx.com/api/xx/xx。可… pathRewrite用'^/api'把'/api'去掉这样既能有正确标识,又能在请求接口的时候去掉api。

Node中间件代理(两次跨域)

代理服务器,需要做以下几个步骤:

  • 接受客户端请求 。
  • 将请求 转发给服务器。
  • 拿到服务器 响应 数据。
  • 将响应 转发给客户端。 image.png

nginx反向代理 实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。 配置nginx代理:blog.csdn.net/chpswg/arti…

————————————————

复习一下跨域的解决方案

  • jsonp
  • cors
  • Node中间件代理(两次跨域)
  • nginx反向代理

CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案 JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。 不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。 日常工作中,用得比较多的跨域方案是cors和nginx反向代理 ————————————————

vue项目打包后 使用nginx部署 vue开发环境配置跨域,一步到位

我开发时的写法总结:

①api.js: 如果后端做了跨域处理,则这里可以直接写成测试环境地址:

     axios.defaults.baseURL = 'http://xxx.xxxx.com:8897/filemanage';

如果跨域,可以在这里配置基础url,然后在vue.config.js里使用proxy反向代理

    axios.defaults.baseURL =process.env.NODE_ENV === 'production' ? '/' : '/api/filemanage';

②vue.config.js

      devServer: {
        host: '0.0.0.0', //局域网和本地访问
        open: true,
        overlay: {
          warnings: false,
          errors: true,
        },
        proxy: {
          ['/api']: {
            target: 'http://xxx.xxxx.com:8897',
            changeOrigin: true,
            pathRewrite: {
              ['^/api']: '',
            },
          },
        },
      },

本地测试地址是没有含有api的,所有,pathRewrite进行重写地址,把api替换成空字符“ ”。