前后端分离开发跨域问题总结
- 一、什么是跨域访问
- 二、解决跨域问题
- 1、Vue前端配置代理解决跨域
- 2、SpringBoot后端配置解决跨域
- 2.1 跨域配置类`CorsConfig`(常用)
- 2.2 Controller添加`@CrossOrigin`注解
- 2.3 添加CORS过滤器`CorsFilter`(常用)
- 2.4 使用SpringSecurity来解决跨域问题
开发需求:
在使用vue uniapp springboot开发微信小程序过程中,也是采用了前后端分离的模式,前端页面及js部署在微信小程序中,后端接口部署在阿里云服务器中,当前端向后端发起请求的时候一定是不符合同源策略的,也就无法访问,就会需要解决跨域问题,实现前后交互。本文系统介绍了跨域问题为什么会出现,以及所有的处理方式。
一、什么是跨域访问
跨域访问,必须先了解一个名词:同源策略
同源策略是指在浏览器端出于安全考量,向服务端发起请求必须满足:协议相同、Host(ip)相同、端口相同的条件,否则访问将被禁止,不满足要求的访问也就被称为跨域访问。
虽然跨域访问被禁止之后,可以在一定程度上提高了应用的安全性,但也为开发带来了一定的麻烦。
跨域,指的是浏览器不能执行其他网站的脚本,是浏览器对JavaScript施加的安全限制。
所谓同源是指:域名、协议、端口均相同,例子如下:
http://www.jumper.com/index.html 调用 http://www.jumper.com/server.PHP (非跨域)
http://www.jumper.com/index.html 调用 http://www.sun.com/server.php (主域名不同:jumper/sun,跨域)
http://abc.jumper.com/index.html 调用 http://def.jumper.com/server.php(子域名不同:abc/def,跨域)
http://www.jumper.com:8080/index.html调用 http://www.jumper.com:8081/server.php(端口不同:8080/8081,跨域)
http://www.jumper.com/index.html 调用 https://www.jumper.com/server.php(协议不同:http/https,跨域)
请注意:localhost 和127.0.0.1虽然都指向本机,但也属于跨域。
二、解决跨域问题
下文是解决跨域问题两种方式:前端、后端,其中后端又包括的方法,用一种即可,无需全部配置使用。
1、Vue前端配置代理解决跨域
在Vue中解决跨域问题比较简单,因为我们每次浏览器发送的请求中,URL的前半部分一定是相同的,比如http://localhost:8080/users与http://localhost:8080/login,我们就可以将他们相同的URL提取出来,封装到axios.defaults.baseURL
中,这样我们在每次请求的时候,就可以将请求地址简写成“/users”这样,相当于是将URL头部进行了一个简单的封装。
request.js
import axios from 'axios'
const request = axios.create({
baseURL: '/api', // 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,其他位置写接口的时候就不要加 '/api'了,否则会出现两个'/api',类似 '/api/api/user'这样的报错,切记!!!
timeout: 5000
})
// request 拦截器 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
// config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
vue.config.js
module.exports = {
devServer: {
host: 'localhost',
open: true, // 自动打开浏览器
// 代理配置表,在这里可以配置特定的请求代理到对应的API接口
proxy: {
'/api': { // 匹配所有以 '/api'开头的请求路径
target: 'http://localhost:8080', // 代理目标的基础路径
// secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, // 支持跨域
pathRewrite: { // 重写路径: 去掉路径中开头的'/api'
'^/api': ''
}
}
}
}
}
2、SpringBoot后端配置解决跨域
2.1 跨域配置类CorsConfig
(常用)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
2.2 Controller添加@CrossOrigin
注解
@RestController
@RequestMapping("users/")
public class IndexController {
@GetMapping
@CrossOrigin
public String users() {
return "users";
}
}
2.3 添加CORS过滤器CorsFilter
(常用)
新建配置类CorsFilterConfig,创建CorsFilter
过滤器,允许跨域
@Configuration
public class CorsConfig {
// 跨域请求处理
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
config.addAllowedOrigin("*");
// config.addAllowedOrigin("http://localhost:8080");
//允许所有请求头
config.addAllowedHeader("*");
//允许所有方法
config.addAllowedMethod("*");
// 为url添加映射路径
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
2.4 使用SpringSecurity来解决跨域问题
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and().cors().configurationSource(corsConfigurationSource())
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());//将csrf令牌存储在cookie中 允许cookie前端获取
}
CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setAllowedOrigins(Arrays.asList("*"));
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}