【已解决】Spring Boot解决跨域问题跨域-看这一篇就够了。使用vue+axios+spring boot前后端分离项目时会出现跨域问题怎么解决
- 经验分享
- 时间:2023-08-13 18:11
- 2498人已阅读
🔔🔔🔔好消息!好消息!🔔🔔🔔
有需要的朋友👉:联系凯哥
场景描述:
使用vue+axios+spring boot前后端分离项目时会出现跨域问题
解决方案,这里使用了四种方案来解决。分别是:
一: 针对单个接口,使用注解@CrossOrigin
二: 全局配置
三: 自定义跨域过滤器
四:通过Response跨域
五:重写ResponseBodyAdvice
六: 使用nginx反向代理服务器解决跨域问题
下面来详细介绍每种方案的配置:
方案一:针对单个接口,使用注解@CrossOrigin
比如我A接口需要支持跨域,在A接口的类上使用@CrossOrigin(origins = "*",maxAge = 3600)
具体代码:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
@CrossOrigin(origins = "*",maxAge = 3600)
public class UserController {
final UserMapper userMapper;
@GetMapping("/getOne/{id}")
public User getOne(@PathVariable("id") Integer id) {
return userMapper.getById(id);
}
}此种方案的优缺点:
优缺点分析此方式虽然虽然实现(跨域)比较简单,但细心的朋友也能发现,使用此方式只能实现局部跨域,当一个项目中存在多个类的话,使用此方式就会比较麻烦(需要给所有类上都添加此注解)。
方案二:全局配置
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration // 一定不要忽略此注解
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否发送 Cookie
.allowedOriginPatterns("*") // 支持域
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"}) // 支持方法
.allowedHeaders("*")
.exposedHeaders("*");
}
}方案三:自定义跨域过滤器
public class CrosFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
String origin = req.getHeader("Origin");
if (!org.springframework.util.StringUtils.isEmpty(origin)) {
//带cookie的时候,origin必须是全匹配,不能使用*
res.addHeader("Access-Control-Allow-Origin", origin);
}
res.addHeader("Access-Control-Allow-Methods", "*");
String headers = req.getHeader("Access-Control-Request-Headers");
// 支持所有自定义头
if (!org.springframework.util.StringUtils.isEmpty(headers)) {
res.addHeader("Access-Control-Allow-Headers", headers);
}
res.addHeader("Access-Control-Max-Age", "3600");
// enable cookie
res.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}3.2:将上面编写的过滤器注册到容器中
/**
* @desc 注册自定义跨域过滤器
* @author guozhongyao
* @date 2020/3/30 15:52
*/
@Bean
public FilterRegistrationBean registerFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.addUrlPatterns("/*");
bean.setFilter(new CrosFilter());
return bean;
}解决方案4:通过 Response 跨域
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
@RestController
public class TestController {
@RequestMapping("/test")
public HashMap<String, Object> test(HttpServletResponse response) {
// 设置跨域
response.setHeader("Access-Control-Allow-Origin", "*");
return new HashMap<String, Object>() {{
put("state", 200);
put("data", "success");
put("msg", "");
}};
}
}解决方案5:ResponseBodyAdvice
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
/**
* 内容是否需要重写(通过此方法可以选择性部分控制器和方法进行重写)
* 返回 true 表示重写
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
/**
* 方法返回之前调用此方法
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
// 设置跨域
response.getHeaders().set("Access-Control-Allow-Origin", "*");
return body;
}
}此实现方式也是全局跨域,它对整个项目中的所有接口有效。
方案六:使用nginx反向代理服务器解决跨域问题
1, 在nginx的conf目录下,创建vhosts文件夹
2, 在nginx.conf 文件中添加 include vhosts/*.conf;

3, vhost目录下创建 abc.conf文件

原理分析
为什么通过以上方法设置之后,就可以实现不同项目之间的正常交互呢?这个问题的答案也很简单,我们之前在说跨域时讲到:“跨域问题本质是浏览器的行为,它的初衷是为了保证用户的访问安全,防止恶意网站窃取数据”,那想要解决跨域问题就变得很简单了,只需要告诉浏览器这是一个安全的请求,“我是自己人”就行了,那怎么告诉浏览器这是一个正常的请求呢?只需要在返回头中设置“Access-Control-Allow-Origin”参数即可解决跨域问题,此参数就是用来表示允许跨域访问的原始域名的,当设置为“*”时,表示允许所有站点跨域访问,如下图所示:

所以以上 六种解决跨域问题的本质都是给响应头中加了一个 Access-Control-Allow-Origin 的响应头而已
总结
跨域问题的本质是浏览器为了保证用户的一种安全拦截机制,想要解决跨域问题,只需要告诉浏览器“我是自己人,不要拦我”就行。它的常见实现方式有 5 种:通过注解实现局部跨域、通过配置文件实现全局跨域、通过 CorsFilter 对象实现全局跨域、通过 Response 对象实现局部跨域,通过 ResponseBodyAdvice 实现全局跨域。