熟悉 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. Inclavare Containers:云原生机密计算的未来

    ​简介:本文为你详细的梳理一次 Inclavare Containers 项目的发展脉络,解读它的核心思想和创新技术. ​ 作为业界首个面向机密计算场景的开源容器运行时,Inclavare Conta ...

  2. WPF 使用 ManipulationDemo 工具辅助调试设备触摸失效问题

    本文将和大家介绍我所在的团队开源的 ManipulationDemo 工具.通过 ManipulationDemo 工具可以提升调试设备触摸失效的效率 此工具在 GitHub 上完全开源,请看 htt ...

  3. Win32 使用 CreateProcess 方法让任务管理器里的命令行不显示应用文件路径

    本文记录一个 Win32 的有趣行为,调用 CreateProcess 方法传入特别的参数,可以让任务管理器里的命令行不显示应用文件路径 开始之前,先看看下面这张有趣的图片 可以看到我编写的 Svca ...

  4. VisualStudio 使用 FastTunnel 辅助搭建远程调试环境

    有时候需要远程调试一些用户问题,期望能使用本机的 Visual Studio 开发环境,调试远程的用户的设备上的应用.这时会遇到的一个问题是如何让本机的 Visual Studio 可以连接上远程的用 ...

  5. WPF 创建空白图片

    本文告诉大家如何在 WPF 创建空白图片,可以创建1像素图片 可以使用 BitmapSource 的 Create 方法创建空白图片 // 限制不能创建小于2x2的图片 const int width ...

  6. SQL server 批量删除表

    select 'drop table '+name+';' from sys.tables declare c cursor forselect NAME from sysobjects where ...

  7. 5.prometheus监控--监控nginx

    1.监控程序环境准备 mkdir /data/docker-compose -p cd /data/docker-compose cat > docker-compose.yaml <&l ...

  8. SpringBoot获取配置:@Value、@ConfigurationProperties方式

    配置文件yml # phantomjs的位置地址 phantomjs: binPath: windows: binPath-win linux: binPath-linux jsPath: windo ...

  9. ITIL是标准吗?

    ITIL不是标准 OGC:是一个推荐的管理框架,一个模版,可根据运维实践自由裁量落地 itil诞生环境:欧美思维.欧美文化.欧美制度.欧美人文习惯.... 对欧美来说可能是最佳实践,但是对中国特色文化 ...

  10. Maven - cmd命令行窗口创建maven项目

    一.构建命令 mvn archetype:generate 当出现以上的命令提示,直接回车下一步即可: 二.输入maven项目的groupId.artifactId.version 三.maven项目 ...