前言

  • 什么是跨域?

​ 简单来说就是有上图这样的问题出现,控制台报错。

为什么会出现跨域?

  • 受到浏览器的同源策略限制,浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。

  • 跨域问题主要分出现在开发环境(本地运行)中的跨域,以及生产环境(部署于线上的环境)中的跨域

开发环境(即本地运行)

在Vue2.0中

  1. 先配置好axios的baseURL,即下面代码段中的 axios.defaults.baseURL = ‘/api/‘,作用是我们每次发送的请求都会带一个/api/的前缀。这段代码可以写在main.js中,也可以写在一个request.js的文件中单独作为axios的配置文件,方便维护。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 配置请求的根路径
axios.defaults.baseURL = '/api/'
// 挂载到原型对象之前 先设置拦截器 通过axios请求拦截器添加token,保证拥有获取数据的权限
axios.interceptors.request.use(config => {
//在 request 拦截器中, 展示进度条 NProgress.start()
NProgress.start()
// 为请求头对象添加Token验证的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem('token')
// 最后都必须 return config
return config
})
// 在 response 拦截器中, 隐藏进度条 NProgress.done()
axios.interceptors.response.use(config => {
NProgress.done()
return config
})
  1. 配置代理,(配置在vue.config.js文件中的proxyTable字段中)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080/', //要解决跨域的接口的域名
secure:false, //如果是https接口,需要配置这个参数
ws: true, //如果要代理 websockets,配置这个参数
changeOrigin: true, // 允许跨域
pathRewrite: {
'^/api': '' // 标识替换,使用 '/api' 代替真实的接口地址,路径重写
}
}
}
}
}
  1. target后面的就是需要请求的网址的公共部分,然后用/apis来代理这个,最后重写一些路径,请求的时候使用的我们的代理的apis来作为前缀。

Uqn3xD.png

在Vue3.0中

  • vue-cli3 脚手架搭建完成后,项目目录中没有 vue.config.js 文件,需要手动创建

    新建一个vue.config.js,配置以下信息,同样可以解决。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    module.exports = {   
    devServer: {
    proxy: {
    '^/api': {
    target: 'http://localhost:8080/',//接口的前缀
    ws:true,//代理websocked
    changeOrigin:true,//虚拟的站点需要更管origin
    pathRewrite:{
    '^/api':''//重写路径
    }
    }
    }
    }
    }

小结

  • changeOrigin: true :开启代理:在本地会创建一个虚假服务器,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端就可以进行数据的交互。

  • apis就是接口实际请求的前缀,去代理了我们的实际的接口前缀的公共部分

  • 比如 请求接口为localhost:8080/getData 我们只需要传入:getData

withCredentials属性

  • 最近在开发调试的过程出现了跨域的另一种情况
  • The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’.

对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“”。这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。

  • 也就是说Access-Control-Allow-Credentials设置为true的情况下
    Access-Control-Allow-Origin不能设置为*

  • ps: 关于指定域名 可以在后端用个array类似的存一个白名单域名列表
    如果有请求 先判断 Origin 是否在白名单里 然后再动态设置 Access-Control-Allow-Origin

  • 前端的解决办法就是将withCredentials属性设为false即可

1
2
3
4
const service = axios.create({
// withCredentials: true, //axios 设置请求自动携带cookie
withCredentials: false, // 不携带cookie请求
})
  • 我的项目是不需要cookie的,如果项目需要携带cookie的话,那么是要后端配置的。

SpringBoot解决跨域问题

方案1

在Spring Boot 中给我们提供了一个注解 @CrossOrigin 来实现跨域,这个注解可以实现方法级别的细粒度的跨域控制。

我们可以在类或者方添加该注解,如果在类上添加该注解,该类下的所有接口都可以通过跨域访问,如果在方法上添加注解,那么仅仅只限于加注解的方法可以访问。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

@Autowired
private UserService userService;

@RequestMapping("/findAll")
public Object findAll() {
return userService.list();
}
}

方案2

在Springboot项目里加上这个配置文件CorsConfig.java,重启之后即可实现跨域访问,前端无需再配置跨域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

// 当前跨域请求最大有效时长。这里默认1天
private static final long MAX_AGE = 24 * 60 * 60;

@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
corsConfiguration.setMaxAge(MAX_AGE);
source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}