SpringBoot解决跨域的超实用方案分享

 更新时间:2023年05月24日 10:05:34   作者:天罡gg  
这篇文章介绍了使用SpringBoot解决跨域问题的方法,并提供了详细的代码示例和解释,适合对跨域问题不太熟悉的读者,感兴趣的小伙伴跟着小编一起来学习吧

一、验证跨域

模拟前端地址:http://localhost:8080/index.html

后端接口地址:http://localhost:8081/auth/test/cors

思路:启动两个springboot项目:8080端口和8081端口,在8080端口的静态资源目录index.html中,对8081端口的接口发起请求,因为端口不同,所以属于跨域,从而就可以验证不同请求(POST或OPTIONS等方法)是否报CORS error !

1. 添加index.html

在 tg-book-web的resources下,新建static\index.html

逻辑:使用ajax发送请求,调用8081的/auth/test/cors接口,如果执行成功,将结果输出到id="result"的div下,如下代码是post请求,后面还会改成options请求测试.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<div id="result">
</div>
</body>
<script type="text/javascript">
    $.ajax({
        url: 'http://localhost:8081/auth/test/cors',
        method: 'post',
        success: function (res) {
            console.log(res)
            $('#result').append('<p>' + res['message'] + '</p>')
        }
    })
</script>
</html>

对index.html不进行接口身份认证
因为我们增加了身份认证AuthInterceptor,所以需要在AuthInterceptor的preHandle过滤掉index.html,如下:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("AuthInterceptor.preHandle:" + request.getServletPath());
    if (request.getServletPath().startsWith("/index.html")) {
        return true;
    }
    ...其它代码
}

2. 增加/auth/test/cors接口

AuthController下增加接口

@PostMapping("/test/cors")
public TgResult<String> testCors() {
    return TgResult.ok();
}

同样,将/auth/test/cors也不进行接口身份认证.
排除身份认证是为了更好的测试跨域,所以同样写在排除"/auth/login"的位置.

registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
                // 排除的请求路径
                .excludePathPatterns("/auth/login", "/auth/test/cors");

3. IDEA启动多个springboot项目

关于如何使用IDEA启动多个springboot项目,我就不演示了,我启动了8080和8081两个端口:

4. 验证POST方法

在浏览器打开 http://localhost:8080/index.html,如下图:

可以看到,8080/index.html通过ajax请求了8081的接口,返回200,说明支持POST请求跨域!

5. 验证OPTIONS方法

OK,正如我开头所说,@CrossOrigin注解对options方法并没有支持跨域,我们来试一试!

只需将index.html中的 【 method: ‘post’】改为【 method: ‘options’】,重启8080服务,然后用同样的方法测试,如下,报CORS error了 🤣

详细报错:

二、拦截器方案

SpringBoot中使用拦截器需要2步:

  • 定义拦截器
  • 注册拦截器,并指定拦截规则

定义拦截器

新增一个拦截器类 CorsInterceptor 实现 HandlerInterceptor 接口

package org.tg.book.web.interceptor;

@Component
public class CorsInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 允许跨域源,全部允许为*,否则写允许请求的源ip
        if (StringUtils.isEmpty(request.getHeader("Origin"))) {
            response.setHeader("Access-Control-Allow-Origin", "*");
        } else {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        }
        response.setHeader("Access-Control-Allow-Credentials", "true");
        // 允许跨域方法:全部允许为*,否则写具体的方法,例如:GET, POST, PUT, DELETE, OPTIONS
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "86400");
        // 允许跨域请求头
        response.setHeader("Access-Control-Allow-Headers", "*");
        // 如果是OPTIONS,不走后续操作,直接返回
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return false;
        }
        return true;
    }
}
  • Access-Control-Allow-Origin: 允许跨域源,全部允许为*,否则写允许请求的源ip。重点:通常会使用白名单机制,只有request.getHeader(“Origin”) 在白名单中才允许跨域。
  • Access-Control-Allow-Methods:允许跨域方法:全部允许为*,否则写具体的方法,例如:GET, POST, PUT, DELETE, OPTIONS

注册拦截器,并指定拦截规则

在原有的InterceptorConfig 中增加注入CorsInterceptor ,并将【跨域拦截器】 放在 【身份认证拦截器】之前,如下:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private CorsInterceptor corsInterceptor;
    @Autowired
    private AuthInterceptor authInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    	// 新增的跨域拦截器
        registry.addInterceptor(corsInterceptor)
        		.addPathPatterns("/**");
        // 身份认证拦截器
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
                // 排除的请求路径
                .excludePathPatterns("/auth/login");
    }
}

去除原来的 @CrossOrigin注解,然后验证,同样,完全支持POST和OPTIONS方法!

三、过滤器方案

新增 CorsFilter 实现Filter接口

public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        if (StringUtils.isEmpty(request.getHeader("Origin"))) {
            response.setHeader("Access-Control-Allow-Origin", "*");
        } else {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        }
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");
        // 如果是OPTIONS,不走后续操作,直接返回
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return;
        }
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
    }
}

新增配置类CorsConfig 注入 CorsFilter

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        return new CorsFilter();
    }
}

注意:测试时先注释上面的 跨域拦截器,然后验证,完全支持POST和OPTIONS方法!

总结

今天我使用了两种方案解决跨域:拦截器和过滤器方案,都是超实用的方案。另外,给你留个作业吧,都做成配置扩展,而不是hard code,例如上面说到的白名单机制,实际就是配置一堆ip,其它也是同理,你可以把你的配置扩展写在留言区里,或者遇到的问题在留言区和我一起讨论,感谢你的阅读,也欢迎你把这篇文章分享给更多的朋友一起阅读。

以上就是SpringBoot解决跨域的超实用方案分享的详细内容,更多关于SpringBoot解决跨域的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Spring中Bean后置处理器(BeanPostProcessor)的使用

    详解Spring中Bean后置处理器(BeanPostProcessor)的使用

    BeanPostProcessor 接口也被称为Bean后置处理器,通过该接口可以自定义调用初始化前后执行的操作方法。本文将详细讲讲它的使用,需要的可以参考一下
    2022-06-06
  • Java 中ThreadLocal类详解

    Java 中ThreadLocal类详解

    什么是ThreadLocal?顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。
    2016-03-03
  • Java操作MongoDB数据库的示例代码

    Java操作MongoDB数据库的示例代码

    这篇文章主要介绍了Java操作MongoDB的示例代码,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-04-04
  • java 计算中位数的实现方法

    java 计算中位数的实现方法

    这篇文章主要介绍了java 计算中位数的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Java数组传递及可变参数操作实例详解

    Java数组传递及可变参数操作实例详解

    这篇文章主要介绍了Java数组传递及可变参数操作,结合实例形式详细分析了java数组参数传递与可变参数相关使用技巧,需要的朋友可以参考下
    2019-09-09
  • SpringBoot工程启动顺序与自定义监听超详细讲解

    SpringBoot工程启动顺序与自定义监听超详细讲解

    这篇文章主要介绍了SpringBoot工程启动顺序与自定义监听,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-11-11
  • IDEA在创建包时如何把包分开实现自动分层(方法详解)

    IDEA在创建包时如何把包分开实现自动分层(方法详解)

    这篇文章主要介绍了IDEA在创建包时如何把包分开实现自动分层,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • Java中用户线程与守护线程的使用区别

    Java中用户线程与守护线程的使用区别

    这篇文章主要介绍了Java中用户线程与守护线程的使用区别,Java语言中无论是线程还是线程池,默认都是用户线程,因此用户线程也被成为普通线程,下文关于其与守护线程的区别详情,需要的小伙伴可以参考一下
    2022-05-05
  • java实现ftp上传 如何创建文件夹

    java实现ftp上传 如何创建文件夹

    这篇文章主要为大家详细介绍了java实现ftp上传的相关资料,教大家如何创建文件夹?具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • Java中的@builder建造者模式详细解析

    Java中的@builder建造者模式详细解析

    这篇文章主要介绍了Java中的@builder建造者模式详细解析,使用 @Builder 注解可以简化手动编写建造者模式的代码,使代码更加简洁易读,它可以自动生成链式调用的方法来设置对象的属性,并且可以在需要时进行可选属性的设置,需要的朋友可以参考下
    2024-01-01

最新评论