专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringBoot 优雅解决 ajax 跨域请求

今天打开页面报错,地址是有效的,但浏览器会报 “No ‘Access-Control-Allow-Origin’ header is present on the requested resource ” 错误页面如下:

90_1.png

这是由于 ajax 跨域请求造成的

什么是跨域

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

How does it works ?

CORS请求(包括预选的带有选项方法)被自动注册到各种 HandlerMapping 。他们处理 CROS 准备请求并拦截 CORS 简单和实际请求,这得益于 CorsProcessor 实现(默认情况下默认DefaultCorsProcessor 处理器),以便添加相关的CORS响应头(如 Access-Control-Allow-Origin )。 CorsConfiguration 允许您指定CORS请求应该如何处理:允许 origins, headers, methods 等。

a、AbstractHandlerMapping#setCorsConfiguration() 允许指定一个映射,其中有几个CorsConfiguration 映射在路径模式上,比如/api/**。

b、子类可以通过重写AbstractHandlerMapping类的getCorsConfiguration(Object, HttpServletRequest)方法来提供自己的CorsConfiguration。

c、处理程序可以实现 CorsConfigurationSource 接口(如ResourceHttpRequestHandler),以便为每个请求提供一个CorsConfiguration。

如何解决

普通跨域请求解决方案

1、 请求接口添加注解 @CrossOrigin(origins = “*”, maxAge = 3600)

说明:origins = “*” origins 值为当前请求该接口的域

2、 通用配置

    /**
     * 跨域请求配置
     * @author chendesheng
     * @create 2019/9/16 19:07
     */
    @Configuration
    public class CorsConfig {

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

        private CorsConfiguration buildconfig(){
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            corsConfiguration.addAllowedHeader("*");
            corsConfiguration.addAllowedMethod("*");
            return corsConfiguration;
        }

    }

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)
            }
        })

此处请求报错:OPTIONS http://localhost:8766/main/currency/sginInState 500

普通跨域的解决方案已经无法解决这种问题,为什么会出现OPTIONS请求呢?

原因:

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

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

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

为何 OPTIONS 请求是500呢?

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

如何解决这个异常?

1、 spring boot项目application.yml中添加

spring:
mvc:
dispatch-options-request: true 

2、 添加过滤器配置

第一步:手写 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 。

具体代码实现:

@Component
public class MyWebConfiguration extends WebMvcConfigurationSupport{
    @Resource
    private RequestFilter requestFilter;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 跨域拦截器
        registry.addInterceptor(requestFilter).addPathPatterns("/**");
    }
}

这样就优雅的解决了 ajax 跨域请求的问题。

文章永久链接:https://tech.souyunku.com/38089

未经允许不得转载:搜云库技术团队 » SpringBoot 优雅解决 ajax 跨域请求

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们