You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway中RouterFunction错误处理与WebClient异常透传咨询

问题1:WebClient异常透传实现标准化错误返回

实现步骤:

  1. 自定义异常类,用来存储下游服务返回的状态码、错误信息、时间戳字段:
// 自定义网关API异常,透传下游错误信息
public class GatewayApiException extends RuntimeException {
    private final int statusCode;
    private final String message;
    private final String timestamp;

    public GatewayApiException(int statusCode, String message, String timestamp) {
        this.statusCode = statusCode;
        this.message = message;
        this.timestamp = timestamp;
    }

    // 此处补充三个字段的getter方法
}
  1. 改造WebClient的状态异常处理逻辑,覆盖所有4xx、5xx错误场景,抛出上述自定义异常:
public Mono<RestNodeCreate> createNode(Mono<RestNodeCreate> node, String token) {
    return webClient
        .post()
        .uri("/nodes")
        .contentType(MediaType.APPLICATION_JSON)
        .header(HttpHeaders.AUTHORIZATION, token)
        .body(node, RestNodeCreate.class)
        .retrieve()
        // 捕获所有4xx、5xx错误状态
        .onStatus(HttpStatus::isError, response -> {
            int status = response.statusCode().value();
            // 如果下游响应头带时间戳可以直接提取,没有就网关侧生成
            String timestamp = response.headers().getFirst("timestamp");
            String finalTimestamp = timestamp == null ? LocalDateTime.now().toString() : timestamp;
            return response.bodyToMono(String.class)
                .flatMap(errorBody -> Mono.error(new GatewayApiException(status, errorBody, finalTimestamp)));
        })
        .bodyToMono(RestNodeCreate.class);
}
  1. 改造Handler层捕获异常,构造符合要求的标准化响应:
public Mono<ServerResponse> createNodes(ServerRequest request) {
    return request.bodyToMono(RestNodeCreate.class)
        .flatMap(newNodeCreate -> {
          if (newNodeCreate.getAccessMethod().equals("TCPIP")) {
            return oldCatalog.createNode(Mono.just(newNodeCreate), getTokenFromRequest(request));
          } else {
            return builNodesToNewCatalog(Mono.just(newNodeCreate))
                .flatMap(newNodeCreate1 -> newCatalog.createNode(Mono.just(newNodeCreate1)));
          }
        })
        .flatMap(o -> ServerResponse.ok().body(Mono.just(o), Object.class))
        // 新增异常处理逻辑,返回标准错误格式
        .onErrorResume(GatewayApiException.class, e -> {
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("timestamp", e.getTimestamp());
            errorResult.put("statuscode", e.getStatusCode());
            errorResult.put("message", e.getMessage());
            return ServerResponse.status(e.getStatusCode())
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(errorResult);
        });
}

如果有多个端点需要统一错误处理,可以直接实现WebExceptionHandler配置全局异常处理器,不需要每个Handler单独加异常处理逻辑。


问题2:Spring Cloud Gateway中能否使用阻塞的RestTemplate和同步@RestController

不建议也不推荐直接使用:

  • Spring Cloud Gateway底层基于Spring WebFlux + Netty非阻塞架构设计,同步@RestController是Spring MVC的Servlet栈组件,和WebFlux环境默认冲突,就算强制切换到Servlet运行模式,也会完全丧失SCG的非阻塞高吞吐优势。
  • 直接在WebFlux环境调用RestTemplate等阻塞API,会占用Netty的事件循环线程,导致请求堆积、吞吐量暴跌,严重时会触发服务雪崩。

如果必须使用阻塞逻辑,需要手动将阻塞操作包裹在Mono.defer()中,并且通过publishOn(Schedulers.boundedElastic())切换到专门的阻塞线程池执行,但这种方案仅适合低频场景,不推荐在网关层大量使用。如果你的业务逻辑以同步阻塞为主,更建议选择Zuul 1等基于阻塞IO设计的网关组件。


内容的提问来源于stack exchange,提问作者kamilguti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:24:05