Springboot如何优雅的解决ajax+自定义headers的跨域请求

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Springboot如何优雅的解决ajax+自定义headers的跨域请求

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!

1、什么是跨域

由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。),凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。

具体可以查看下表:

Springboot如何优雅的解决ajax+自定义headers的跨域请求

2、springboot如何解决跨域问题

1.普通跨域请求解决方案:

①请求接口添加注解@CrossOrigin(origins = “http://127.0.0.1:8020", maxAge = 3600)

说明:origins = “http://127.0.0.1:8020" origins值为当前请求该接口的域

②通用配置(所有接口都允许跨域请求)

新增一个configration类 或 在Application中加入CorsFilter和CorsConfiguration方法


@Configuration  
public class CorsConfig {  
    private CorsConfiguration buildConfig() {  
        CorsConfiguration corsConfiguration = new CorsConfiguration();  
        corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 2允许任何头
        corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等) 
        return corsConfiguration;  
    }  

    @Bean  
    public CorsFilter corsFilter() {  
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  
        source.registerCorsConfiguration("/**", buildConfig()); // 4  
        return new CorsFilter(source);  
    }  
}  

2.ajax自定义headers的跨域请求


$.ajax({
        type:"GET",
        url:"http://localhost:8766/main/currency/sginInState",
        dataType:"JSON",
        data:{
            uid:userId
        },
        beforeSend: function (XMLHttpRequest) {
            XMLHttpRequest.setRequestHeader("Authorization", access_token);
        },
        success:function(res){
            console.log(res.code)
        }
    })

此时请求http://localhost:8766/main/currency/sginInState接口发现OPTIONS http://localhost:8766/main/currency/sginInState 500错误,普通跨域的解决方案已经无法解决这种问题,为什么会出现OPTIONS请求呢?

Springboot如何优雅的解决ajax+自定义headers的跨域请求

原因

浏览器会在发送真正请求之前,先发送一个方法为OPTIONS的预检请求 Preflighted requests 这个请求是用来验证本次请求是否安全的,但是并不是所有请求都会发送,需要符合以下条件:

  • 请求方法不是GET/HEAD/POST
  • POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
  • 请求设置了自定义的header字段
  • POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain

    对于管理端的接口,我有对接口进行权限校验,每次请求需要在header中携带自定义的字段(token),所以浏览器会多发送一个OPTIONS请求去验证此次请求的安全性。

    为何OPTIONS请求是500呢?

    OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,而后台校验token字段时 token为NULL,所以验证不通过,抛出了一个异常。

    那么我们现在来解决这种问题:

    ① spring boot项目application.yml中添加

    
    spring:
    mvc:
    dispatch-options-request: true 
    

    注意:这种解决方案可能在某些情况下并不能解决OPTIONS问题,原因可能是环境问题,也可能是复杂的自定义filter过滤器配置问题等。

    ②添加过滤器配置

    第一步:手写RequestFilter请求过滤器配置类此类需要实现HandlerInterceptor类,HandlerInterceptor类是org.springframework.web.servlet.HandlerInterceptor下的。

    具体代码实现:

    
    @Component
    public class RequestFilter implements HandlerInterceptor {
       public boolean preHandler(HttpServletRequest request,HttpServletResponse response,Object handler){
           response.setHeader("Access-Control-Allow-Origin", "*");
           response.setHeader("Access-Control-Allow-Credentials", "true");
           response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
           response.setHeader("Access-Control-Max-Age", "86400");
           response.setHeader("Access-Control-Allow-Headers", "Authorization");
           // 如果是OPTIONS请求则结束
           if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
               response.setStatus(HttpStatus.NO_CONTENT.value());
               return false;
           }
           return true;
       }
    }
    

    第二步:手写MyWebConfiguration此类需要继承WebMvcConfigurationSupport。

    注意:WebMvcConfigurationSupport是2.x版本以上的,1.x版本为WebMvcConfigurerAdapter 。

    具体代码实现:

    
    @Component
    public class MyWebConfiguration extends WebMvcConfigurationSupport{
        @Resource
        private RequestFilter requestFilter;
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 跨域拦截器
            registry.addInterceptor(requestFilter).addPathPatterns("/**");
        }
    }
    
    Springboot如何优雅的解决ajax+自定义headers的跨域请求

    此时我们就完美解决了ajax+自定义headers的跨域请求了,欢迎随时交流学习。

    阅****读(点击文字可跳转)

    1. 

    ****2. ****

    3.

    4.

    看完本文有收获?请转发分享给更多人

    Springboot如何优雅的解决ajax+自定义headers的跨域请求

    原文始发于微信公众号(Java知音):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Springboot如何优雅的解决ajax+自定义headers的跨域请求


     上一篇
    基于SpringBoot开发一个Restful服务,实现增删改查功能 基于SpringBoot开发一个Restful服务,实现增删改查功能
    点击上方“Java知音”,选择“置顶公众号” 技术文章第一时间送达! 作者:虚无境 cnblogs.com/xuwujing/p/8260935.html 推荐阅****读 1.  ****2. **** 3.  ****4
    下一篇 
    SpringBoot+Mybatis多模块(module)项目搭建教程 SpringBoot+Mybatis多模块(module)项目搭建教程
    点击上方“Java知音”,选择“置顶公众号” 技术文章第一时间送达! 作者:枫本非凡 cnblogs.com/orzlin/p/9717399.html 推荐阅****读 1.  ****2. **** 3.  ****4.