前端初学SpringBoot系列(四)跨域的复习

1,994 阅读4分钟

背景

今天合作多年的后端小伙伴过来和我探讨跨域的问题,他比较好奇:线上环境是因为NGINX帮前端处理了跨域的问题,配置好了Access-Control-Allow-Origin,Access-Control-Allow-Credentials,那么本地调试时候,你是怎么处理的呢, 然后我俩一顿白话o( ̄︶ ̄)o,于是就有了今天的这篇文章,发现我原来对vue-cli3关于代理的部分知识理解有所偏差。 我俩讨论完之后,我本地做了个测试跟他讲这个事,前两节的项目做了后端服务器,本地起了一个前端的项目:

很明显前后端触发了跨域,端口号不同,理论上会报错的啊,但是竟然没有报错:

这就很搞笑了,我给人解释一通,解释错了,仔细看了一下network发现多了几个奇怪的东西,不知道谁给自动加的,解决了本来应该报错的问题,于是就要好好搞搞这个问题了。

同源策略

在研究跨域问题之前,肯定是要了解一下前置知识的,浏览器安全的基石:同源策略 同源的三个原则:

  1. 同一个协议,httphttps都不一样
  2. 同一个域名,localhost127.0.0.1都不一样,www.demo.comdemo.com也不一样
  3. 同一个端口,localhost:8080localhost都不一样,后者默认端口是80 以上三个要素就是的概念,所谓的跨域就是违背了上述的三个原则。虽然跨域看似不安全,但合理的绕过规则,却具有很重要的意义,那么怎么解决这个问题呢?

CORS

解决跨域的方法,web端来说有多种处理方式,但是今天暂且先不研究其他的多种方式,只研究一个主流的方式CORSCross Origin Resources Sharing,跨域资源共享。 对于前端来说,基本上直接使用了Vue-cli脚手架,用了几个配置项帮我们掩盖了很多细节,帮我我们愉快的和后端进行跨域联调😄

解决跨域的两个端

一般来说说,本地联调是两个端都可以处理这个问题。

前端跨域的配置

想看跨域的解决方案,那自然要把正常的报错的情况模拟出来,一开始我还怀疑axios的问题(╯︵╰),于是采用了原生AJAX写了:

let xhr = new XMLHttpRequest()
xhr.open("GET","http://localhost:8082/api/users",true);
xhr.send(null);
xhr.onload = function(e) {
    var xhr = e.target;
    console.log('xhr.responseText', xhr.responseText);
}

如果后端不做处理的话,这次自然触发跨域的报错了:

仔细观察报错信息:

使用axios发请求一样报错,说明捣鬼的是其他地方帮我处理了跨域,最后发现是脚手架内部集成的webpack,帮我们做了很多事情,其中有个配置项与今天的主角跨域有关,在新版脚手架中,配置项都在vue.config.js中进行配置

module.exports = {
  devServer: {
    //proxy解决了,跨域
    proxy: {
      '/api': {
        target: 'http://localhost:8082/',
        ws: true,
        changeOrigin: true 
      }
    }
  }
}

真正起作用的是devServer.proxy属性,而不是我想的changeOrigin,开启是true是说把target中的地址起一个虚拟服务器来虚拟那个接口地址。

The origin of the host header is kept when proxying by default, you can set changeOrigin to true to override this behaviour. It is useful in some cases like using name-based virtual hosted sites.

默认是false

后端解决跨域

新版的springboot有注解可以完成在响应头里面加上跨域的各种配置项:

@CrossOrigin("把允许的源放到这里")

加上这句注解之后:

一个重要结论

对比以上几个network的不同之处,有两个请求头很有意思:

  1. Sec-Fetch-Mode 解释了请求的模式。

一般来说现代浏览器支持CORS了,该值为cors,官方说总共有6个值可供选择:

Sec-Fetch-Mode: cors
Sec-Fetch-Mode: navigate
Sec-Fetch-Mode: nested-navigate
Sec-Fetch-Mode: no-cors
Sec-Fetch-Mode: same-origin
Sec-Fetch-Mode: websocket
  1. Sec-Fetch-Site 解释了请求的源和要请求的资源之间的关系。 这个值有4个值可供选择:
Sec-Fetch-Site: cross-site
Sec-Fetch-Site: same-origin
Sec-Fetch-Site: same-site
Sec-Fetch-Site: none

结论:

  • 解决跨域问题,前端真正起作用的是devServer.proxy
  • 后端处理时,cross-site与响应头里面的Access-Control-Allow-Origin配套使用
  • 前端处理时,直接就是same-origin,使用了一个http代理中间件

工具的封装实在太好了,隐藏了太多细节了,懂得皮毛实在没有用啊,ε=(´ο`*)))唉,只有继续深入才能走得更远~~~~~~~~

本文使用 mdnice 排版