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

Spring Reactive WebClient调用AKS服务返回404错误求助

问题分析与解决方案

问题现象

使用Spring Reactive WebClient调用Azure Kubernetes Service(AKS)上的服务时,返回nginx的404 Not Found错误,但调用虚拟机规模集(VMSS)上的同逻辑服务正常;更换为RestClient调用AKS服务则完全正常。

可能原因与排查解决步骤

1. URL拼接一致性问题

WebClient与RestClient的URL拼接逻辑存在细微差异,若baseUrl和uri的斜杠格式不一致,可能导致最终请求URL不符合AKS ingress的路由规则。

  • 排查方式:给WebClient添加请求拦截器,打印最终请求URL,与RestClient的请求URL对比:
    WebClient webClient = WebClient.builder()
        .filter(ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("WebClient 请求URL: {}", clientRequest.url());
            return Mono.just(clientRequest);
        }))
        // 其他原有配置
        .build();
    
  • 解决方案:统一baseUrl和uri的斜杠格式,比如:
    • 若baseUrl结尾带斜杠(如http://aksdomainname.net/aks-gateway/svc/catalog/),则uri开头去掉斜杠(改为v1/ast)
    • 或baseUrl结尾不带斜杠(如http://aksdomainname.net/aks-gateway/svc/catalog),uri开头带斜杠(保持/v1/ast)

2. 请求头重复/覆盖问题

WebClient同时使用defaultHeader和headers(h -> h.putAll(httpHeaders))可能导致请求头重复(比如Content-Type或Accept出现多个值),而AKS的nginx网关对重复头的处理与VMSS不同,导致路由失败。

  • 排查方式:添加拦截器打印WebClient的请求头,与RestClient的请求头对比:
    .filter(ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
        log.info("WebClient 请求头: {}", clientRequest.headers());
        return Mono.just(clientRequest);
    }))
    
  • 解决方案:合并头配置,避免重复设置:
    WebClient webClient = WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder()
            .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(100 * 1024 * 1024)).build())
        .baseUrl(aksUrl)
        .clientConnector(connector)
        .build();
    
    // 请求时统一设置所有头
    final String resp = webClient.post().uri(uri)
        .bodyValue(request)
        .headers(h -> {
            h.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            h.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
            h.putAll(httpHeaders); // 仅添加自定义头,避免重复
        })
        // 其他原有处理逻辑
        .block();
    

3. HttpClient配置差异

WebClient使用Reactor Netty HttpClient,而RestClient默认使用JDK/Apache HttpClient,两者的默认配置(如HTTP版本、重定向策略、连接池)可能存在差异,导致AKS网关不兼容。

  • 排查方式:先去掉WebClient的自定义HttpClient配置,使用默认连接器测试:
    WebClient webClient = WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder()
            .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(100 * 1024 * 1024)).build())
        .baseUrl(aksUrl)
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).build();
    
  • 解决方案:若默认配置有效,再逐步添加自定义配置,同时强制使用HTTP/1.1(AKS ingress常依赖HTTP/1.1):
    HttpClient httpClient = HttpClient.create()
        .protocol(HttpProtocol.H11) // 强制HTTP/1.1
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 300_000)
        .responseTimeout(Duration.ofMillis(300_000));
    final ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
    

4. 请求体序列化差异

WebClient与RestClient的JSON序列化规则可能不同(比如字段顺序、空值处理),导致AKS服务无法正确识别请求,进而返回404。

  • 排查方式:拦截WebClient的请求体,打印后与RestClient的请求体对比:
    .filter(ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
        clientRequest.body().insert(clientRequest.headers(), Context.of())
            .flatMap(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                DataBufferUtils.release(dataBuffer);
                log.info("WebClient 请求体: {}", new String(bytes));
                return Mono.empty();
            }).subscribe();
        return Mono.just(clientRequest);
    }))
    
  • 解决方案:统一WebClient与RestClient的ObjectMapper配置:
    // 使用与RestClient相同的ObjectMapper实例
    ObjectMapper objectMapper = new ObjectMapper();
    // 配置序列化规则(如忽略空值、字段顺序等)
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    
    ExchangeStrategies strategies = ExchangeStrategies.builder()
        .codecs(configurer -> {
            configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper));
            configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper));
            configurer.defaultCodecs().maxInMemorySize(100 * 1024 * 1024);
        }).build();
    
    WebClient webClient = WebClient.builder()
        .exchangeStrategies(strategies)
        // 其他配置
        .build();
    

5. AKS Ingress路由规则检查

若以上步骤都无效,需检查AKS的nginx ingress配置,确认是否对请求的特定属性(如请求头、URL大小写、HTTP方法)有严格限制,确保WebClient的请求完全符合路由规则。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:21:04