SpringBoot业务开发 06、SpringBoot跨域问题解决方案

举报
长路 发表于 2022/11/28 19:51:58 2022/11/28
【摘要】 文章目录前言起因Springboot解决方案1、添加@CrossOrigin2、全局CORS配置(实现WebMvcConfigurer的addCorsMappings方法)3、基于filter的跨域实现(筛选白名单来进行跨域请求)4、基于Nginx参考文章 前言 本篇博客是使用SpringBoot解决跨域问题的解决方案,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客目录索引(持续更新)

@[toc]

前言

本篇博客是使用SpringBoot解决跨域问题的解决方案,若文章中出现相关问题,请指出!

所有博客文件目录索引:博客目录索引(持续更新)

起因

当我们前后端分离时,前端发送请求就非常有可能出现跨域问题。

image-20210830101840544

image-20210830102432465

此时浏览器在本地的5500端口运行,此时若是发送给本地的9999就会出现跨域问题!

image-20210830102026105

描述:浏览器中有同源策略,其指的是发送请求的协议、域名以及端口必须与向后端的请求一致,否则就会跨域问题。想要解决跨域问题,就需要后端添加响应头Access-Control-Allow-Origin属性。



Springboot解决方案

1、添加@CrossOrigin

注解源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {

	@Deprecated
	String[] DEFAULT_ORIGINS = {"*"};

	@Deprecated
	String[] DEFAULT_ALLOWED_HEADERS = {"*"};

	@Deprecated
	boolean DEFAULT_ALLOW_CREDENTIALS = false;

	@Deprecated
	long DEFAULT_MAX_AGE = 1800;

	String[] value() default {};

	@AliasFor("value")
	String[] origins() default {};

	String[] originPatterns() default {};

	String[] allowedHeaders() default {};

	String[] exposedHeaders() default {};

	RequestMethod[] methods() default {};

	String allowCredentials() default "";

	long maxAge() default -1;

}
String[] origins: 允许来源域名的列表,例如 'www.jd.com',匹配的域名是跨域预请求 Response 头中的 'Access-Control-Aloow_origin' 字段值。不设置确切值时默认支持所有域名跨域访问。
String[] allowedHeaders: 跨域请求中允许的请求头中的字段类型, 该值对应跨域预请求 Response 头中的 'Access-Control-Allow-Headers' 字段值。 不设置确切值默认支持所有的header字段(Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma)跨域访问。
String[] exposedHeaders: 跨域请求请求头中允许携带的除Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma这六个基本字段之外的其他字段信息,对应的是跨域请求 Response 头中的 'Access-control-Expose-Headers'字段值。
RequestMethod[] methods: 跨域HTTP请求中支持的HTTP请求类型(GETPOST...),不指定确切值时默认与 Controller 方法中的 methods 字段保持一致。
String allowCredentials: 该值对应的是是跨域请求 Response 头中的 'Access-Control-Allow-Credentials' 字段值。浏览器是否将本域名下的 cookie 信息携带至跨域服务器中。默认携带至跨域服务器中,但要实现 cookie 共享还需要前端在 AJAX 请求中打开 withCredentials 属性。
long maxAge: 该值对应的是是跨域请求 Response 头中的 'Access-Control-Max-Age' 字段值,表示预检请求响应的缓存持续的最大时间,目的是减少浏览器预检请求/响应交互的数量。默认值1800s。设置了该值后,浏览器将在设置值的时间段内对该跨域请求不再发起预请求。

使用方式

//方式一:在类上(表明该类所有方法都能够支持跨域)
@CrossOrigin
class public class UserController {}

//方式二:细粒度在方法上(表明该方法支持跨域)
@RestController
class public class UserController {
    
    @RequestMapping("/user")
    @CrossOrigin
    public String query(){
        ...
    }
}


2、全局CORS配置(实现WebMvcConfigurer的addCorsMappings方法)

定义全局CORS配置,来对指定模块进行跨域支持,类似于筛选器,我们在这里可以进行重写方法来实现针对指定映射地址来进行设置跨域:

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {

    /**
     * 解决跨域问题
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/user/**")  //指定的映射地址
                .allowedHeaders("*") //允许携带的请求头
                .allowedMethods("*") //允许的请求方法
                .allowedOrigins("*");  //添加跨域请求头 Access-Control-Allow-Origin,值如:"https://domain1.com"或"*"
    }
}


3、基于filter的跨域实现(筛选白名单来进行跨域请求)

好处:基于这种方式的话我们能够对指定的url进行筛选来达到允许进行跨域请求的方式!!!

/**
 * @author ChangLu
 * @date 2021/08/30 11:29
 **/
@Component
public class CorsFilter extends OncePerRequestFilter {

    private static List<String> whiteList = new ArrayList<>();//跨域白名单
    static {
        whiteList.add("http://127.0.0.1:5500");
//        whiteList.add("http://jshopx.jd.com");
//        whiteList.add("http://mall.yao.jd.com");
//        whiteList.add("http://yao-shop.jd.com");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //请求的地址
        String originUrl = request.getHeader("origin");
        //查看是否在白名单内
        boolean allow = whiteList.contains(originUrl);
        if(allow){
            response.setHeader("Access-Control-Allow-Origin", originUrl);
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
            response.setHeader("Access-Control-Max-Age", "1800");//30分钟
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type");
            filterChain.doFilter(request, response);
        }else{
            //对于非白名单域名的请求,不予进行访问,不然还会进入到controller方法中执行对应的逻辑
            return;
        }
    }
}

OncePerRequestFilter实际上则是实现了Filter,本质就是一个Filter过滤器,只不过这个也如同其名字一样在每次请求时只执行一次过滤,同样放行操作是执行的filterChain.doFilter()方法。



4、基于Nginx

在Nginx中添加以下的配置来解决跨域

location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

    if ($request_method = 'OPTIONS') {
        return 204;
    }
}


参考文章

[1]. CORS与@CrossOrigin详解:提供了两种方案,一种是@CrossOrigin注解来进行解决

[2]. SpringBoot——》WebMvcConfigurerAdapter详解:详细介绍了Spring对于Springmvc的配置类,可在该配置类中实现对应的方法来进行添加功能

[3]. OncePerRequestFilter原理简介

er详解](https://blog.csdn.net/weixin_43453386/article/details/83623242):详细介绍了Spring对于Springmvc的配置类,可在该配置类中实现对应的方法来进行添加功能

[3]. OncePerRequestFilter原理简介

[4]. SpringBoot项目针对跨域问题的三种解决方案

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。