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

前言

本篇博客是使用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请求类型(GET、POST...),不指定确切值时默认与 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项目针对跨域问题的三种解决方案

我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
Q群:851968786 我们可以一起探讨学习
注明:转载可,需要附带上文章链接

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot提供了多种解决跨域问题的方法。其中一种方法是使用@CrossOrigin注解来实现方法级别的细粒度的跨域控制。你可以在类或者方法上添加该注解。如果在类上添加该注解,该类下的所有接口都可以通过跨域访问。如果在方法上添加注解,那么仅仅只限于加注解的方法可以访问。示例代码如下: @RestController @RequestMapping("/user") @CrossOrigin public class UserController { @Autowired private UserService userService; @RequestMapping("/findAll") public Object findAll(){ return userService.list(); } } 另一种方法是实现WebMvcConfigurer接口。这种方式需要注意的是,CorFilter、WebMvcConfigurer和@CrossOrigin需要SpringMVC 4.2以上版本才支持,对应Spring Boot 1.3版本以上。上面前两种方式属于全局CORS配置,后两种属于局部CORS配置。如果使用了局部跨域,会覆盖全局跨域的规则,所以可以通过@CrossOrigin注解来进行细粒度更高的跨域资源控制。无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域。 #### 引用[.reference_title] - *1* *3* [SpringBoot解决跨域问题的六种方式](https://blog.csdn.net/qq_46028126/article/details/123721540)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBoot项目针对跨域问题的三种解决方案](https://blog.csdn.net/weixin_45721835/article/details/124590962)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长路 ㅤ   

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值