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

从Zuul迁移到Spring Cloud Gateway:ServerHttpRequest转HttpServletRequest问题

问题原因

你遇到的ClassCastException是因为测试中Mock的是ServerHttpRequest通用接口实例,而非Servlet环境特有的ServletServerHttpRequest实现类。只有当Spring Cloud Gateway运行在Tomcat这类Servlet容器中时,exchange.getRequest()才会返回ServletServerHttpRequest实例,直接强转非该类型的实例必然触发转换异常。

解决方案

方案1:测试时正确Mock Servlet环境的请求/响应

修改测试代码,直接Mock Servlet环境专属的请求、响应实现类,确保强转逻辑能正常执行:

private GatewayFilterChain filterChain
private static ServerWebExchange exchange;

def setup() {
    exchange = mock(ServerWebExchange.class)
    // Mock Servlet环境特有的请求响应实现类
    ServletServerHttpRequest servletRequest = mock(ServletServerHttpRequest.class)
    ServletServerHttpResponse servletResponse = mock(ServletServerHttpResponse.class)
    // Mock Jakarta规范的请求响应对象
    HttpServletRequest jakartaRequest = mock(HttpServletRequest.class)
    HttpServletResponse jakartaResponse = mock(HttpServletResponse.class)
    
    filterChain = mock(GatewayFilterChain.class)
    
    when(filterChain.filter(exchange)).thenReturn(Mono.empty())
    when(exchange.getRequest()).thenReturn(servletRequest)
    when(exchange.getResponse()).thenReturn(servletResponse)
    // 关联到Jakarta规范的对象,适配checkRequest方法参数
    when(servletRequest.getServletRequest()).thenReturn(jakartaRequest)
    when(servletResponse.getServletResponse()).thenReturn(jakartaResponse)
}

方案2:在过滤器中安全转换,避免直接强转

为让过滤器代码更健壮,先判断实例类型再执行转换,同时修正请求链流转逻辑(原代码返回Mono.empty()会直接终止请求链,不符合网关过滤器预期):

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 先校验是否为Servlet环境的请求响应
    if (!(exchange.getRequest() instanceof ServletServerHttpRequest) 
        || !(exchange.getResponse() instanceof ServletServerHttpResponse)) {
        log.warn("当前环境不支持Servlet请求响应,跳过授权检查");
        return chain.filter(exchange);
    }
    
    ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest)exchange.getRequest();
    ServletServerHttpResponse serverHttpResponse = (ServletServerHttpResponse)exchange.getResponse();
    
    if (shouldFilter(exchange)) {
        try {
            log.debug("Invoking authorization interceptor");
            if (!checkRequest(
                    serverHttpRequest.getServletRequest(),
                    serverHttpResponse.getServletResponse(),
                    null)) {
                return Mono.error(new RuntimeException("Invalid request"));
            }
            return chain.filter(exchange);
        } catch (Exception exception) {
            log.error(ERROR_MESSAGE, exception);
            return Mono.error(exception);
        }
    }
    // 允许未命中过滤规则的请求继续流转
    return chain.filter(exchange);
}

方案3:通过Exchange属性直接获取Servlet请求(备用)

在Servlet环境下,Spring Cloud Gateway会将Jakarta规范的HttpServletRequest和HttpServletResponse存入ServerWebExchange的属性中,可直接通过属性键获取:

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    HttpServletRequest jakartaRequest = exchange.getAttribute(ServerWebExchangeUtils.CLIENT_REQUEST_ATTR);
    HttpServletResponse jakartaResponse = exchange.getAttribute(ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR);
    
    if (jakartaRequest == null || jakartaResponse == null) {
        log.warn("无法获取Servlet请求响应,跳过授权检查");
        return chain.filter(exchange);
    }
    
    if (shouldFilter(exchange)) {
        try {
            log.debug("Invoking authorization interceptor");
            if (!checkRequest(jakartaRequest, jakartaResponse, null)) {
                return Mono.error(new RuntimeException("Invalid request"));
            }
            return chain.filter(exchange);
        } catch (Exception exception) {
            log.error(ERROR_MESSAGE, exception);
            return Mono.error(exception);
        }
    }
    return chain.filter(exchange);
}

该方式无需强转ServerHttpRequest,代码更简洁,但仅适用于Servlet环境。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:18:13