SpringCloud WebClient调用微服务API时URI识别异常(400错误)
WebClient调用API时URI格式错误(缺失http后双斜杠)导致400 Bad Request
问题现象
使用WebClient调用其他微服务API时抛出400错误,错误日志显示请求URI为http:/localhost:8082/Checkuser/252,缺失了http后的第二个斜杠,导致URI格式非法,请求失败。
错误日志详情
2023-01-23T17:10:17.261+08:00 ERROR 114017 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 400 Bad Request from UNKNOWN ] with root cause org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 400 Bad Request from UNKNOWN at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:309) ~[spring-webflux-6.0.3.jar:6.0.3] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): *__checkpoint ⇢ 400 BAD_REQUEST from GET http:/localhost:8082/Checkuser/252 [DefaultWebClient] Original Stack Trace: at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:309) ~[spring-webflux-6.0.3.jar:6.0.3] at org.springframework.web.reactive.function.client.DefaultClientResponse.lambda$createException$1(DefaultClientResponse.java:213) ~[spring-webflux-6.0.3.jar:6.0.3] at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:106) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxOnErrorReturn$ReturnSubscriber.onNext(FluxOnErrorReturn.java:162) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:122) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2071) ~[reactor-core-3.5.1.jar:3.5.1] at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.5.1.jar:3.5.1] at
业务代码
Boolean result=webClientBuilder.build().get() .uri(uriBuilder -> uriBuilder .path("http://localhost:8082/Checkuser/{id}")//"http://localhost:8082/Checkuser/{id}") .build(252)) .retrieve() .bodyToMono(Boolean.class) .block(); //make syn request if(Boolean.FALSE.equals(result)){ throw new IllegalAccessException("User score to low");
配置类代码
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; @Configuration public class webclientconfig { @Bean public WebClient webClient(){ return WebClient.builder().build(); } @Bean @LoadBalanced public WebClient.Builder loadBalancedWebClientBuilder(){ return WebClient.builder(); } }
问题原因与解决方法
原因
错误地使用uriBuilder.path()方法拼接包含协议、主机的完整URL,path()仅用于设置URI的路径部分,它会对传入字符串做规范化处理,导致http://被错误解析为http:/。
正确写法
有两种可行的修正方式:
方式1:直接传入完整URL到uri()
无需通过UriBuilder构建,直接将完整URL及参数传入uri()方法:
Boolean result = webClientBuilder.build().get() .uri("http://localhost:8082/Checkuser/{id}", 252) .retrieve() .bodyToMono(Boolean.class) .block();
方式2:通过UriBuilder分部分构建URI
如果需要使用UriBuilder,应分别设置协议、主机、端口和路径:
Boolean result = webClientBuilder.build().get() .uri(uriBuilder -> uriBuilder .scheme("http") .host("localhost") .port(8082) .path("/Checkuser/{id}") .build(252)) .retrieve() .bodyToMono(Boolean.class) .block();
额外优化建议
既然已经配置了@LoadBalanced的WebClient.Builder,若调用的是注册到服务中心的微服务,可直接用服务名代替具体主机地址:
// 假设微服务注册名为checkuser-service Boolean result = webClientBuilder.build().get() .uri("http://checkuser-service/Checkuser/{id}", 252) .retrieve() .bodyToMono(Boolean.class) .block();
内容的提问来源于stack exchange,提问作者user20112858
相关产品推荐
相关产品推荐

