配置Spring Boot API接口超时时间(五种)

06-01 1323阅读

1、简介

在开发API接口时,配置API接口的超时时间是一项非常重要的任务。超时时间的设置对于确保系统的稳定性和响应性至关重要。当客户端发送请求到服务器时,如果服务器由于某些原因(如数据库查询缓慢、外部服务调用失败等)无法及时响应,那么设置合理的超时时间可以防止服务器资源被长时间占用,从而避免系统崩溃或性能下降。

在Spring Boot中,有多种方式可以配置API接口的超时时间。针对不同的应用场景,选择正确的配置方式,可以确保系统在面对各种复杂场景时都能保持高效和稳定。

介绍如下几种API超时情况的配置:

  • 事务超时时间配置

    如果你的当前的API接口涉及到事务相关,那么我们可以通过设置设置的超时时间来确保由于数据库缓慢要引起的超时情况。

    • 基于Resilience4j的超时保护机制

      我们可以通过Resilience4j提供的超时机制来设置有效的超时时间。

      • 异步请求超时

        如果你当前请求是异步请求,那么我们可以通过配置异步超时时间来限制接口等待时间。

        • HTTP Client超时配置

          我们将介绍3种HTTP Client超时的配置,分别是RestTemplate,RestClient,WebClient。

          • 基于NGINX代理超时配置

            通常我们的后端接口一般会通过NGINX进行反向代理,在这种情况下,我们可以在其代理上配置超时时间。

            2、实战案例

            2.1 事务超时配置

            我们可以在数据库调用中实现请求超时的一种方法是利用Spring的@Transactional注解。该注解具有一个可以设置的超时属性。该属性的默认值为-1,相当于没有设置任何超时。

            @Transactional(timeout = 1)
            public List query() {
              this.userRepository.findById(8L).ifPresent(System.out::println) ;
              try {
                TimeUnit.SECONDS.sleep(1) ;
              } catch (InterruptedException e) {}
              return this.userRepository.findAll() ;
            }
            

            如上配置注解中配置超时时间为1s,内部执行时先根据id查询,此时能正常执行,当休眠1s后,再次执行数据库操作将抛出超时异常。

            首先,我们进行如下异常配置:

            @ExceptionHandler(TransactionTimedOutException.class)
            public ResponseEntity txTimeout(TransactionTimedOutException ex) {
              return ResponseEntity.ok("请求超时: " + ex.getMessage()) ;
            }
            

            测试接口

            @GetMapping
            public ResponseEntity query() {
              return ResponseEntity.ok(this.userService.query()) ;
            }
            

            测试结果

            配置Spring Boot API接口超时时间(五种)

            以上我们利用了事务的超时时间来保护接口。

            2.2 基于Resilience4j的超时保护机制

            Resilience4j提供了一个TimeLimiter模块,专门用来处理超时保护的。

            首先,引入下面依赖:

              io.github.resilience4j
              resilience4j-spring-boot3
              2.2.0
            
            

            接下来,通过注解配置需要保护的接口

            @TimeLimiter(name = "queryUser", fallbackMethod = "fallbackQuery")
            @GetMapping
            public CompletionStage query() {
              return CompletableFuture.supplyAsync(() -> {
                try {
                  // 模拟耗时操作
                  TimeUnit.SECONDS.sleep(2) ;
                } catch (InterruptedException e) {}
                return ResponseEntity.ok("success") ;
              }) ;
            }
            public CompletionStage fallbackQuery(Throwable e) {
              return CompletableFuture.completedStage(ResponseEntity.ok(e.getMessage())) ;
            }
            

            说明:

            name:在配置文件中定义的超时相关配置,如果配置文件中没有配置则使用默认的配置。

            fallbackMethod:当发生超时现象将调用的降级方法。

            注意:方法的返回值必须是CompletionStage类型。

            最后,配置超时

            resilience4j:
              timelimiter:
                instances:
                  #该名称为上面注解中的name
                  queryUser:
                    timeout-duration: 1s
            

            测试结果

            配置Spring Boot API接口超时时间(五种)

            此种方式是不是非常的简单好用,一个注解搞定。

            2.3 异步请求超时配置

            当我们的API接口是异步请求时,我们可以直接在配置文件中对异步请求的超时时间进行配置:

            spring:
              mvc:
                async:
                  request-timeout: 1s
            

            异步请求接口

            @GetMapping("/async")
            public Callable async() {
              return () -> {
                try {
                  TimeUnit.SECONDS.sleep(10) ;
                } catch (InterruptedException e) {
                  return "任务中断 - " + e.getMessage() ;
                }
                return "异步请求成功" ;
              } ;
            }
            

            测试结果

            配置Spring Boot API接口超时时间(五种)

            虽然这里休眠了10s,但在1s后,直接输出了异常信息。

            2.4 HTTP Client超时配置

            这里我们将介绍3种接口调用的超时配置,分别是:RestTemplate,RestClient已经WebClient,其中RestTemplate与RestClient是基于阻塞式调用并且RestClient是Spring6.1版本开始提供的;而WebClient则是基于响应式的调用(非阻塞)。官方推荐使用WebClient。

            RestTemplate超时配置

            @Bean
            RestTemplate restTemplate(RestTemplateBuilder builder) {
              return builder
                  // 连接超时配置
                  .connectTimeout(Duration.ofSeconds(1))
                  // 读取超时配置
                  .readTimeout(Duration.ofSeconds(1))
                  .build() ;
            }
            

            这是最简单的配置,你还可以通过如下工厂方式配置

            @Bean
            RestTemplate restTemplate() {
              ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.defaults()
                  .withConnectTimeout(Duration.ofSeconds(1))
                  .withReadTimeout(Duration.ofSeconds(1));
              RestTemplate restTemplate = new RestTemplate(
                ClientHttpRequestFactoryBuilder.detect().build(settings)) ;
              return restTemplate ;
            }
            

            根据你的环境选择不同的方式进行配置。

            RestClient超时配置

            RestClient的配置方式与上面的RestTemplate差不多。

            @Bean
            RestClient restClient() {
              ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.defaults()
                  .withConnectTimeout(Duration.ofSeconds(1))
                  .withReadTimeout(Duration.ofSeconds(1)) ;
              return RestClient
                  .builder()
                  .requestFactory(ClientHttpRequestFactoryBuilder.detect().build(settings))
                  .build() ;
            }
            

            最后,我们再来介绍官方推荐的WebClient。

            WebClient超时配置

            首先,我们要引入以下的依赖:

              org.springframework.boot
              spring-boot-starter-webflux
            
            

            下面进行超时配置

            @Bean
            WebClient webClient() {
              HttpClient httpClient = HttpClient.create()
                  .doOnConnected(conn -> conn
                      .addHandlerLast(new ReadTimeoutHandler(1))
                      .addHandlerLast(new WriteTimeoutHandler(1))) ;
              return WebClient.builder()
                  .clientConnector(new ReactorClientHttpConnector(httpClient ))
                  .build() ;
            }
            

            下面我们通过WebClient进行接口调用进行测试

            访问接口

            @GetMapping("/client")
            public String client() {
              try {
                TimeUnit.SECONDS.sleep(3) ;
              } catch (InterruptedException e) {
                return "任务中断 - " + e.getMessage() ;
              }
              return "success" ;
            }
            

            通过WebClient访问该接口

            private final WebClient webClient ;
            this.webClient
              .get()
              .uri("http://localhost:8080/api/users/client")
              .retrieve()
              .bodyToMono(String.class)
              // 当发生错误时会自动调用该方法进行恢复继续执行
              .onErrorResume(ex -> {
                return Mono.just("发生错误: " + ex.getMessage()) ;
              }) 
              .subscribe(System.out::println) ;
            

            测试结果

            io.netty.handler.timeout.ReadTimeoutException: null
            发生错误: null
            

            以上就是关于HTTP Client的超时配置。

            2.5 基于NGINX代理超时配置

            通过NGINX反向代理配置超时时间

            location / {
              proxy_pass http://127.0.0.1:8080;
              proxy_connect_timeout 1s;  # 连接超时时间为30秒
              proxy_send_timeout 1s;     # 发送请求超时时间为60秒
              proxy_read_timeout 1s;     # 读取响应超时时间为60秒
            }
            

            当发生超时时,我们这里通过日志查看:

            [error] 11172#27080: *1 upstream timed out 
              (10060: A connection attempt failed because the connected 
                party did not properly respond after a period of time, 
                  or established connection failed because connected 
                  host has failed to respond) while reading 
                  response header from upstream, 
                  client: 127.0.0.1, server: localhost, 
                  request: "GET /api/users/client HTTP/1.1", 
                  upstream: "http://127.0.0.1:8080/api/users/client", 
                  host: "localhost:1080"
            

            当发生异常,我们还可以进行如下的配置,进行友好提示:

            location / {
              proxy_pass http://127.0.0.1:8080;
              proxy_connect_timeout 1s;  # 连接超时时间为30秒
              proxy_send_timeout 1s;     # 发送请求超时时间为60秒
              proxy_read_timeout 1s;     # 读取响应超时时间为60秒
              # 指定自定义错误页面
              error_page 504 /timeout.html;
              # 指定自定义错误页面的位置
              location = /timeout.html {
                root D:/all/html/;
                internal;
              }
            }
            
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码