使用Spring的Reactive WebClient对三方接口进行调用,发现请求数据不能正常返回。由于此三方接口有严格的请求Header校验,怀疑是header没有传正确。
HttpClient httpClient = HttpClient.create();
eactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
WebClient client = WebClient.builder().clientConnector(connector).build();
Flux<String> flux = client.post()
.uri(URI.create(TEST_URL))
.header(HttpHeaders.ACCEPT,"*/*")
.header(HttpHeaders.ACCEPT_LANGUAGE,"zh-CN,en-US;q=0.7,en;q=0.3")
.header(HttpHeaders.ACCEPT_ENCODING,"gzip,deflate,sdch")
.header(HttpHeaders.CONTENT_TYPE,"application/x-www-form-urlencoded; charset=UTF-8")
.header(HttpHeaders.HOST,"target.com")
.header(HttpHeaders.USER_AGENT,UserAgents.randomUserAgent())
.retrieve()
.onStatus(HttpStatus::isError, response -> {
throw new RuntimeException(response.statusCode().getReasonPhrase());
})
.bodyToFlux(String.class)
.timeout(Duration.ofSeconds(5))
.onErrorResume(throwable -> Flux.just("Error Request: "+throwable.getMessage()));
通过抓包发现果然设置的header没有生效。查看WebClient方法,发现设置多个header时不能调用header()进行设置,而是调用headers()。
Flux<String> flux = client.post()
.uri(URI.create(TEST_URL))
.headers((header)->{
header.set(HttpHeaders.ACCEPT,"*/*");
header.set(HttpHeaders.ACCEPT_LANGUAGE,"zh-CN,en-US;q=0.7,en;q=0.3");
header.set(HttpHeaders.ACCEPT_ENCODING,"gzip,deflate,sdch");
header.set(HttpHeaders.CONNECTION,"keep-alive");
header.set(HttpHeaders.CONTENT_TYPE,"application/x-www-form-urlencoded; charset=UTF-8");
header.set(HttpHeaders.HOST,"target.com");
header.set(HttpHeaders.USER_AGENT,UserAgents.randomUserAgent());
})
.retrieve()
.onStatus(HttpStatus::isError, response -> {
throw new RuntimeException(response.statusCode().getReasonPhrase());
})
.bodyToFlux(String.class)
.timeout(Duration.ofSeconds(5))
.onErrorResume(throwable -> Flux.just("Error Request: "+throwable.getMessage()));
由于业务需要,我在此处每次需要对header设置不同的值。如果不需要,可以对WebClient的header进行统一默认设置。
至此,接口能够正常请求并响应数据了。但是响应的数据打印却是乱码。
第一反应是返回数据编码问题,将WebClient接收数据修改为字节数组bodyToFlux(byte[].class)
,手动再对字节数据指定UTF-8字符集转换为String,发现仍是乱码。
然而奇怪的是之前使用Apache HttpClient相同的请求打印结果却显示正常,没有乱码。抓取两种客户端请求包分析,发现请求参数和响应完全相同。抓包工具Fidder中对响应体都会提示一个“响应数据已编码,点击进行解码“。突然想起请求头中包含gzip。怀疑响应数据是因为进行了gzip压缩,导致WebClient打印出来时乱码。
于是将代码中请求头的ACCEPT_ENCODING
中的gzip去掉。再次请求,发现响应打印正常,不再乱码。
但是要开启gzip怎么办呢?查阅WebClient相关文档,只需完成以下配置即可:
HttpClient httpClient = HttpClient.create().compress(true);