springboot 如何解决cross跨域请求的问题

 更新时间:2021年10月13日 08:42:11   作者:jwolf2  
这篇文章主要介绍了springboot 如何解决cross跨域请求的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

springboot 解决cross跨域请求

1.使用ajax发送跨域请求接口时

接口能正常接收到请求并响应,但是无法正常展示响应数据。跨域请求时会在有一个特别的请求头origin(请求来源)。

浏览器认为这是不安全的。需要在被跨域请求的那个接口,响应时加上加上几个响应头让浏览器允许跨域请求的响应数据展示。

springboot准备了一个过滤器来实现这个操作。(如下:8081有个ajax请求8888的接口,需要在8888加上过滤器)

2.在被跨域请求的一方配置

一个CrosFilter过滤器到spring里即可

 @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8081"); // 允许的域名白名单,可以*
        corsConfiguration.addAllowedHeader("*"); // 允许任何头
        corsConfiguration.addAllowedMethod(HttpMethod.POST); // 允许哪些类型请求,可以*
        corsConfiguration.addExposedHeader("my-header");//自定义请求头
        corsConfiguration.setAllowCredentials(true);//是否允许携带cookie
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/sys/generator/list", corsConfiguration); // 哪些path的接口可以被跨域请求
        source.registerCorsConfiguration("/sys/generator/code", corsConfiguration);
        return new CorsFilter(source);
    }

3.再次测试

响应头主要多了这些,也能正常接收到响应数据了

4.对于只有个别需要开放跨域请求的接口可以这样玩

@CrossOrigin的参数跟CrosFilter参数设置过滤器一致。

5.其它解决跨域请求的常用方法

使用Nginx反向代理 或前端不跨域请求,后端专门开放一个API接口供前端调用,接口以httpClient请求数据

Spring解决cross domain

Spring4:

在requestMapping中使用注解。 @CrossOrigin(origins = “http://localhost:9000”)

全局实现 .定义类继承WebMvcConfigurerAdapter

public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/*").allowedOrigins("*"); } } 

将该类注入到容器中:

<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

Spring3旧版本:

在org.springframework.web.servlet.DispatcherServlet.doDispatch中会根据根据request来获取HandlerExecutionChain,SpringMVC在获取常规的处理器后会检查是否为跨域请求,如果是则替换原有的实例。

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 Object handler = getHandlerInternal(request);
 if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } 

检查的方法也很简单,即检查请求头中是否有origin字段

public static boolean isCorsRequest(HttpServletRequest request) { return (request.getHeader(HttpHeaders.ORIGIN) != null); } 

请求接着会交由 HttpRequestHandlerAdapter.handle来处理,根据handle不同,处理不同的逻辑。前面根据请求头判断是一个跨域请求,获取到的Handler为PreFlightHandler,其实现为:

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { corsProcessor.processRequest(this.config, request, response); } 

继续跟进

@Override
public boolean processRequest(CorsConfiguration config, HttpServletRequest request, HttpServletResponse response)
  throws IOException {
 if (!CorsUtils.isCorsRequest(request)) {
  return true; } ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response); ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request); if (WebUtils.isSameOrigin(serverRequest)) { logger.debug("Skip CORS processing, request is a same-origin one"); return true; } if (responseHasCors(serverResponse)) { logger.debug("Skip CORS processing, response already contains \"Access-Control-Allow-Origin\" header"); return true; } boolean preFlightRequest = CorsUtils.isPreFlightRequest(request); if (config == null) { if (preFlightRequest) { rejectRequest(serverResponse); return false; } else { return true; } } return handleInternal(serverRequest, serverResponse, config, preFlightRequest); } 

此方法首先会检查是否为跨域请求,如果不是则直接返回,接着检查是否同一个域下,或者response头里是否具有Access-Control-Allow-Origin字段或者request里是否具有Access-Control-Request-Method。

如果满足判断条件,则拒绝这个请求。

由此我们知道,可以通过在检查之前设置response的Access-Control-Allow-Origin头来通过检查。我们在拦截器的preHandle的处理。加入如下代码:

response.setHeader("Access-Control-Allow-Origin", "*"); 

此时浏览器中OPTIONS请求返回200。但是依然报错:

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

我们注意到:在request的请求头里有Access-Control-Request-Headers:accept, content-type,但是这个请求头的中没有,此时浏览器没有据需发送请求。尝试在response中加入:

response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

执行成功:

Object {userId: 123, userName: “adminUpdate-wangdachui”}

至此:我们通过分析原理使SpringMVC实现跨域,原有实现以及客户端代码不需要任何改动。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot实现接口幂等性的4种方案

    SpringBoot实现接口幂等性的4种方案

    这篇文章主要介绍了SpringBoot实现接口幂等性的4种方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Spring学习之开发环境搭建的详细步骤

    Spring学习之开发环境搭建的详细步骤

    本篇文章主要介绍了Spring学习之开发环境搭建的详细步骤,具有一定的参考价值,有兴趣的可以了解一下
    2017-07-07
  • 如何在SpringBoot 中使用 Druid 数据库连接池

    如何在SpringBoot 中使用 Druid 数据库连接池

    这篇文章主要介绍了SpringBoot 中使用 Druid 数据库连接池的实现步骤,帮助大家更好的理解和学习使用SpringBoot,感兴趣的朋友可以了解下
    2021-03-03
  • 使用kotlin集成springboot开发的超详细教程

    使用kotlin集成springboot开发的超详细教程

    目前大多数都在使用java集成 springboot进行开发,本文演示仅仅将 java换成 kotlin,其他不变的情况下进行开发,需要的朋友可以参考下
    2021-09-09
  • SpringBoot 如何使用 JWT 保护 Rest Api 接口

    SpringBoot 如何使用 JWT 保护 Rest Api&nbs

    使用spring-boot开发RESTful API非常的方便,在生产环境中,对发布的 API 增加授权保护是非常必要的,现在我们来看如何利用JWT技术为API 增加授权保护,保证只有获得授权的用户才能够访问 API,感兴趣的朋友跟随小编一起看看吧
    2024-02-02
  • java高并发ScheduledThreadPoolExecutor类深度解析

    java高并发ScheduledThreadPoolExecutor类深度解析

    这篇文章主要为大家介绍了java高并发ScheduledThreadPoolExecutor类源码深度解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Spring Boot常用功能Profile详解

    Spring Boot常用功能Profile详解

    SpringBootProfile是一个很常用的功能,我们可以通过为开发/测试/生产环境配置不同的profile来实现配置隔离,那么在SpringBoot项目中是如何实现profile功能的呢
    2022-07-07
  • SpringMVC自定义类型转换器实现解析

    SpringMVC自定义类型转换器实现解析

    这篇文章主要介绍了SpringMVC自定义类型转换器实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • java中BigDecimal和0比较的示例代码

    java中BigDecimal和0比较的示例代码

    这篇文章主要介绍了java中BigDecimal和0比较的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java版给爱人表白的玫瑰花程序代码

    Java版给爱人表白的玫瑰花程序代码

    这篇文章主要讲解了Java版给爱人表白的玫瑰花程序代码,具有很好的参考价值,希望对大家有所帮助,一起跟随小编过来看看吧
    2018-05-05

最新评论