You need to enable JavaScript to run this app. Spring微服务间使用WebClient调用报400 Bad Request 直连下游正常
优惠活动
大模型
产品
解决方案
定价
更多

Spring微服务间使用WebClient调用报400 Bad Request 直连下游正常

问题根因
  • 核心是WebClient构建请求URI时的API误用:将带http://协议、主机名的完整URL字符串传入了UriBuilder.path()方法。
    path()方法的设计用途是拼接相对路径片段,它不会自动把传入的字符串解析成包含协议、主机的绝对URI,只会把整段字符串当成普通路径片段处理,直接破坏了标准URI的结构(标准URI结构为协议://主机/路径?参数):原本应该放在URI主机位的ratings-data-service被错误放置到路径位置,最终引发连锁问题:
    1. 负载均衡组件在把服务名ratings-data-service解析为实际实例地址localhost:7654时,无法正确识别原URI的结构,也就没法同步更新请求的Host头字段,最终发出的请求里Host头仍残留服务名字符串。
    2. 下游ratings-data-service的Web服务器(Netty)收到请求时,会校验请求行与Host头的匹配性,发现Host头和当前服务的监听地址不匹配,直接返回400 Bad Request。
  • 直接访问接口可正常返回的原因:浏览器构造请求时会严格遵循URI规范,自动将Host头设置为访问的目标地址localhost:7654,完全符合服务端校验规则,因此不会触发400错误。
修复方案
  • 修正URI构建逻辑,不要把完整绝对URL传入path()方法,可以参考以下两种正确写法重写业务方法:
    1. 通过UriBuilder分步骤设置URI属性,同时将List类型的电影ID展开为可变参数传入queryParam,避免把整个List对象当成单个参数值处理:
      fun findRatingByMovieId(movieIds: List<String>) : Flux<Rating> {
          return webClient.build()
              .get()
              .uri { uribuilder ->
                  uribuilder.scheme("http")
                      .host("ratings-data-service")
                      .path("/ratings/list")
                      .queryParam("movieIds", *movieIds.toTypedArray())
                      .build()
              }
              .retrieve()
              .bodyToFlux(Rating::class.java)
      }
      
    2. 直接拼接完整URI字符串传入uri()方法,避免UriBuilder的误用:
      fun findRatingByMovieId(movieIds: List<String>) : Flux<Rating> {
          val queryStr = movieIds.joinToString("&") { "movieIds=$it" }
          val targetUri = "http://ratings-data-service/ratings/list?$queryStr"
          return webClient.build()
              .get()
              .uri(targetUri)
              .retrieve()
              .bodyToFlux(Rating::class.java)
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 23:45:04