盘点 Spring Boot 解决跨域请求的几种办法

spring,boot · 浏览次数 : 0

小编点评

本文主要介绍了跨域请求及其解决方法。跨域请求是指在浏览器中访问不同源(协议、域名或端口号不一致)的web服务器资源时出现的异常。为了解决这个问题,文章提出了三种方法: 1. 使用过滤器的方式全局配置跨域请求。创建一个实现了Filter接口的过滤器,然后在Servlet容器中注册该过滤器,并指定拦截路径。 2. 通过全局配置类实现跨域访问。重写WebMvcConfigurer接口中的addCorsMappings方法,添加允许跨域访问的源、方法和头部信息。 3. 使用@CrossOrigin注解实现局部跨域访问。在需要跨域访问的方法上加上@CrossOrigin注解,可以设置更小的粒度,如允许特定的源和最大缓存时间。 文章还提到了跨域访问在开发环境中的重要性,以及在生产环境中可能需要关闭或限制跨域访问。最后,提供了参考资料以便进一步学习。

正文

熟悉 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 解决跨域请求的几种办法相似的内容:

盘点 Spring Boot 解决跨域请求的几种办法

熟悉 web 系统开发的同学,对下面这样的错误应该不会太陌生。 之所以会出现这个错误,是因为浏览器出于安全的考虑,采用同源策略的控制,防止当前站点恶意攻击 web 服务器盗取数据。 01、什么是跨域请求 同源策略,简单的说就是当浏览器访问 web 服务器资源时,只有源相同才能正常进行通信,即协议、域

SpringBoot SpringSecurity 介绍(基于内存的验证)

SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘 SpringBoot已经为用户采用默认配置,只需要引入pom依赖就能快速启动Spring Security。 目的:验证请求用户的身份,提供安全访问 优势:基于Spring,配置方便,减少大

SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘

SpringBoot 集成 SpringSecurity + MySQL + JWT 无太多理论,直接盘 一般用于Web管理系统 可以先看 SpringBoot SpringSecurity 基于内存的使用介绍 本文介绍如何整合 SpringSecurity + MySQL + JWT 数据结构 数

盘点下华为大佬的技术拷问下我没招架住的一些问题

行情动荡不安,看着同组曾经一块并肩战斗过的开发同事们陆续被迫离职,我最近几个月也多少的思维活跃了些,有些惴惴不安,不知何时会轮到自己。想着即使暂时轮不到自己,也要有着被裁后能立马找到下家工作的能力,一直坐以待毙终究沦为案板上的羔羊。 据说华为社招技术岗基本都是OD了,正式的很少很少,但是OD的面试流

盘点学英语的困惑1:反义疑问句

对于反义疑问句: # 1.反义疑问句语法规则 第一个知识点是:在反义疑问句中,前面肯定描述,反义就是否定去问;前面否定描述,反义就是肯定去问。 简单记忆口诀就是“前肯后否,前否后肯”,举例来说: ```shell He is a teacher, isn't he? 他是一名教师,不是吗? He i

盘点Python 中字符串的常用操作

摘要:盘点 Python 中字符串的几个常用操作,对新手极度的友好。 本文分享自华为云社区《盘点 Python 中字符串的常用操作,对新手极度友好》,作者:TT-千叶 。 在 Python 中字符串的表达方式有四种 一对单引号一对双引号一对三个单引号一对三个双引号a = ‘abc’b= “abc”c

盘点10个最受欢迎IntelliJ IDEA主题,必有一款适合你!

选择一款适合自己的主题,这样每天工作才不会累!下面给大家精选了一批优秀的主题,并配上案例截图。如果有你喜欢的,那就赶紧去下载吧! Darcula 这是IntelliJ IDEA默认的暗色主题,适合长时间使用,减少眼睛疲劳。 Material Theme UI 一款基于谷歌Material Desig

[转帖]通信圈周盘点:电信业务收入达14504亿元;新华三中国企业网交换机市场份额超三成

http://blog.itpub.net/31545813/viewspace-2930213/ 本周,1~11月电信业务收入累计完成14504亿元;新华三2022前三季度中国企业网交换机市场份额超三成;华为数通跻身2022 Gartner®魔力象限“领导者”;Aruba SD-WAN及云安全产品

[转帖]通信圈周盘点:我国5G用户数占比已超三成;锐捷网络登陆深交所创业板

http://blog.itpub.net/31545813/viewspace-2925108/ 本周,我国5G用户数占比已超三成;华为5G + Wi-Fi + IoT融合园区网方案在陕西某高校全球首局成功商用;新华三港澳地区2022用户大会于今日圆满落幕;“网络设备龙头”锐捷网络登陆深交所创业板

痞子衡嵌入式:盘点国内Cortex-M内核MCU厂商高主频产品(2023)

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是国内Cortex-M内核MCU厂商高主频产品。 在 2021 年初痞子衡写了篇 《盘点国内Cortex-M内核MCU厂商高性能产品》,搜罗了当时市面上主频不低于 96MHz 的 CM 核国产 MCU。如今过去了两年,痞子衡又一次梳理了国