【已解决】Spring Boot解决跨域问题跨域-看这一篇就够了。使用vue+axios+spring boot前后端分离项目时会出现跨域问题怎么解决
- 经验分享
- 时间:2023-08-13 18:11
- 2260人已阅读
🔔🔔🔔好消息!好消息!🔔🔔🔔
有需要的朋友👉:联系凯哥
场景描述:
使用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 实现全局跨域。