熟悉 web 系统开发的同学,对下面这样的错误应该不会太陌生。

之所以会出现这个错误,是因为浏览器出于安全的考虑,采用同源策略的控制,防止当前站点恶意攻击 web 服务器盗取数据。

01、什么是跨域请求

同源策略,简单的说就是当浏览器访问 web 服务器资源时,只有源相同才能正常进行通信,即协议、域名、端口号都完全一致,否则就属于跨域请求。当发起跨域请求时,服务端是能收到请求并正常返回结果的,只是结果被浏览器拦截了。

像上文中,浏览器访问的站点是http://127.0.0.1:8848/,而站点内发起的接口请求源是http://localhost:8080,因为不同源,所以报跨域请求异常。

由此可见,想要实现接口请求的正常访问,浏览器的访问站点源和接口请求源,必须得一致。

事实上,在现在流行的前后端分离的开发模式下,很难做到请求源高度一致,那怎么办呢?

答案肯定是有办法啦!

虽然浏览器出于安全的考虑,默认采用同源策略控制,以便减少服务器被恶意攻击的机会,但是开发者可以通过CORS协议在浏览器内实现站内跨域请求访问。

实现很简单,通过在 web 服务器中增加一个特殊的Header响应属性来告诉浏览器解除跨域的限制,如果浏览器支持CORS并且判断允许通过的话,此时发起的跨域请求就可以正常展示了。

常用的 Header 响应属性如下:

Header 属性 作用
Access-Control-Allow-Origin 设置允许跨域请求的请求源,比如www.xxx.com
Access-Control-Max-Age 设置预检请求的结果能被缓存的时间,单位秒,比如1800
Access-Control-Allow-Methods 设置允许跨域请求的方法,比如GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers 设置允许跨域请求的头部信息,比如Content-Type, Accept
Access-Control-Allow-Credentials 设置是否允许携带凭证(比如cookies),参数值只能是true或者不设置

带着以上的信息,我们就一起来了解一下如何在 Spring Boot 应用中实现跨域访问。

02、解决方案

2.1、方法一:采用过滤器的方式全局配置

采用过滤器的方式来实现所有接口支持跨域请求,是一种比较通用的做法,也是 Java web 项目中常用的方法,实现过程如下!

首先,创建一个实现自Filter接口的过滤器,示例如下:

public class CrossFilter implements Filter {

    /**
* 允许跨域的白名单域名
*/
private final static Set<String> ALLOW_DOMAINS = new HashSet<>(); static {
ALLOW_DOMAINS.add("http://127.0.0.1:8848");
} @Override
public void init(FilterConfig config) throws ServletException {} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
// 获取客户端原始请求域
String origin = request.getHeader("Origin");
String originDomain = removeHttp(origin);
if(ALLOW_DOMAINS.contains(originDomain)){
// 在响应对象中,添加CROS协议相关的header属性
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,HEAD,PUT,PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Authorization,authorization");
response.setHeader("Access-Control-Allow-Credentials","true");
}
//继续往下传递
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() {} /**
* 移除http协议头部
* @param url
* @return
*/
public static String removeHttp(String url){
return url.replace("http://", "").replace("https://", "");
} }

接着,将其注册到Servlet容器中,示例如下:

@Configuration
public class FilterConfig { /**
* 添加CrossFilter过滤器
* @return
*/
@Bean
public FilterRegistrationBean crossFilterBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setName("crossFilter"); // 指定过滤器名称
registration.setFilter(new CrossFilter()); // 指定过滤器实现类
registration.setUrlPatterns(Collections.singleton("/*"));// 指定拦截路径
registration.setOrder(1);// 指定顺序
return registration;
}
}

最后,启动服务后,再到浏览器中发起跨域请求,看看效果如下。

从结果上看,浏览器成功进行了跨域请求,并展示了服务器返回的结果。

2.2、方法二:通过全局配置类实现跨域访问

在 Spring Boot 应用,除了采用过滤器的方式实现跨域访问外,我们还可以通过全局配置类实现跨域访问。

实现方法也非常简单,只需要重写WebMvcConfigurer接口中的addCorsMappings方法即可,示例如下:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer { @Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600)
.allowedHeaders("Origin", "Accept", "Content-Type", "Authorization")
.allowCredentials(true);
}
}

其中allowedOrigins("*")表示对所有请求都允许跨域访问。

2.3、方法三:通过CrossOrigin注解实现跨域访问

某些场景,如果不希望所有的接口都能跨域访问,只想在部分接口上放开跨域访问。此时,可以通过 Spring Boot 提供的@CrossOrigin注解,在对应的方法上加上该注解,即可实现跨域访问。

示例如下:

@RestController
public class UserController { @Autowired
private UserService userService; @CrossOrigin
@PostMapping(value = "/queryAll")
public List<User> queryAll(){
List<User> result = userService.queryAll();
return result;
}
}

如果使用在controller类上,表示当前类下的所有接口方法都允许跨域访问。

同时,@CrossOrigin注解也支持设置更小的粒度,示例如下:

@CrossOrigin(origins = "http://domain.com", maxAge = 1800)

更多的属性行为,内容如下:

  • origins: 允许的源列表,多个源可以使用逗号分隔
  • methods: 允许的 HTTP 方法列表
  • allowedHeaders: 允许的请求头列表,默认情况下,允许所有请求头
  • allowCredentials:设置是否允许携带凭证
  • maxAge: 预检请求的缓存时间(以秒为单位)

03、小结

最后总结一下,在 Spring Boot 服务中可以通过过滤器或者配置类实现全局跨域访问,也可以通过@CrossOrigin注解实现局部跨域访问。

跨域访问的配置,更适合在开发环境中方便前后端进行联调对接。为了安全起见,在上生产的时候,建议将其关闭掉或者做限制。

此外,想要获取项目源代码的小伙伴,可以点击:跨域请求,即可获取取项目的源代码。

04、参考

1.https://cloud.tencent.com/developer/article/1655583

2.https://cloud.tencent.com/developer/article/1924258

写到最后

不会有人刷到这里还想白嫖吧?点赞对我真的非常重要!在线求赞。加个关注我会非常感激!

本文已整理到技术笔记中,此外,笔记内容还涵盖 Spring、Spring Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL、微服务等技术栈。

需要的小伙伴可以点击 技术笔记 获取!

盘点 Spring Boot 解决跨域请求的几种办法的更多相关文章

  1. Spring Boot + Vue 跨域请求问题

    使用Spring Boot + Vue 做前后端分离项目搭建,实现登录时,出现跨域请求 Access to XMLHttpRequest at 'http://localhost/open/login ...

  2. spring boot 解决跨域访问

    package com.newings.disaster.shelters.configuration; import org.springframework.context.annotation.B ...

  3. spring mvc \ spring boot 允许跨域请求 配置类

    用@Component 注释下,随便放个地方就可以了 package com.chinaws.wsarchivesserver.core.config; import org.springframew ...

  4. Spring boot 解决跨域问题

    import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.we ...

  5. spring boot 解决 跨域 的两种方法 -- 前后端分离

    1.前言 以前做项目 ,基本上是使用 MVC 模式 ,使得视图与模型绑定 ,前后端地址与端口都一样 , 但是现在有些需求 ,需要暴露给外网访问 ,那么这就出现了个跨域问题 ,与同源原则冲突, 造成访问 ...

  6. spring boot处理跨域请求代码

    @Configuration @WebFilter(filterName = "CorsFilte") public class CorsFilter implements Fil ...

  7. Spring Boot 允许跨域设置失败的问题深究

    在公司开发过程中,一个前后端分离的项目遇见了跨域的问题. 前端控制台报错:No 'Access-Control-Allow-Origin' header is present on the reque ...

  8. spring @CrossOrigin解决跨域问题

    阅读目录: 一.跨域(CORS)支持: 二.使用方法: 1.controller配置CORS 2.全局CORS配置 3.XML命名空间 4.How does it work? 5.基于过滤器的CORS ...

  9. js中ajax如何解决跨域请求

    js中ajax如何解决跨域请求,在讲这个问题之前先解释几个名词 1.跨域请求 所有的浏览器都是同源策略,这个策略能保证页面脚本资源和cookie安全 ,浏览器隔离了来自不同源的请求,防上跨域不安全的操 ...

  10. Ajax 调用webservice 解决跨域请求和发布到服务器后本地调用成功外网失败的问题

        webservice 代码 /// <summary> /// MESService 的摘要说明 /// </summary> [WebService(Namespac ...

随机推荐

  1. Quick Audience组织和工作空间功能解读

    近期,Quick Audience完成了权限系统全面升级,可以解决集团企业不同品牌.不同运营组织,不同消费者运营的诉求,精细化保障企业数据访问安全,提升管控的灵活度.​ Quick Audience整 ...

  2. ChatGPT 眼中的程序员

    1 你如何看待程序员这个行业 程序员这个行业在现代社会扮演着非常重要的角色.作为一个技术驱动的职业,程序员们负责开发.设计和维护软件和应用程序,这些技术改变了我们的生活方式.商业模式和社会互动方式. ...

  3. FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass

    ​libass是一个适用于ASS和SSA格式(Advanced Substation Alpha/Substation Alpha)的字幕渲染器,支持的字幕类型包括srt.ass等,凡是涉及到给视频画 ...

  4. DE10-Lite锁相环使用教程

    DE10-Lite锁相环使用教程 目标:本文讲述如何在Quartus里设置和例化一个锁相环. 引言 锁相环(PLL)是一种闭环频率控制电路,用于比较压控振荡器的输入信号和输出信号之间的相位差. 负反馈 ...

  5. Quartus prime 的安装步骤:

  6. CF746 期望+逆序对

    Link 题意:给定一个 \(1\) 到 \(n\) 的排列,等概率选一段区间 \([l, r]\) 随机排序,求期望逆序对数. \[E = \dfrac{\sum(cnt_{[1, n]} - cn ...

  7. Asp-Net-Core开发笔记:进一步实现非侵入性审计日志功能

    前言 上次说了利用 AOP 思想实现了审计日志功能,不过有同学反馈还是无法实现完全无侵入,于是我又重构了一版新的. 回顾一下:Asp-Net-Core开发笔记:实现动态审计日志功能 现在已经可以实现对 ...

  8. docker 完美部署gitea

    效果: docker-compose version: "3" networks: gitea: external: false services: server: image: ...

  9. golang 中 strings 包的 Replace 用法介绍笔记

    函数申明: func Replace(s, old, new string, n int) string 官方描述为: 返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换 ...

  10. 简易的 Linux 流量实时监控工具 watch+ifstat

    非常简单小巧的流量实时监控工具,贵在不需要安装,Linux 操作系统自带,在不出外网的环境中很是实用. watch -d ifstat eth1 如果连 ifstat 都没有的环境中也可以使用 ifc ...