【问题标题】:How to compress JSON request body with WebClient?如何使用 WebClient 压缩 JSON 请求正文?
【发布时间】:2020-06-22 05:44:27
【问题描述】:

我需要使用WebClient 执行POST,并且服务器需要压缩正文。我检查了之前提出的herehere 的问题,但没有一个问题能帮助我理解需要做什么。

我的代码如下所示:

webClient.post()
    .bodyValue(requestBody)
    .retrieve()
    .bodyToMono(Response.class)

我想发送使用 gzip 压缩的 requestBody。我们使用 RestTemplate 和自定义 GZipFilter 来做这件事,但我现在看不到如何使用 WebClient 来做这件事。

【问题讨论】:

    标签: spring spring-boot spring-webflux


    【解决方案1】:

    我已经实现了示例代码来帮助您解决这个问题。您需要清理它并适应您的需求,但我已经对此进行了测试,它确实有效。

    第一步是实现Encoder<T>,其中<T> 是您要编码的对象的类型。在我的示例中,我使用的是 JsonNode。

    public class GzipEncoder extends AbstractEncoder<JsonNode> {
    
        public GzipEncoder() {
            super(MediaType.APPLICATION_JSON);
        }
    
        @Override
        public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
            return MediaType.APPLICATION_JSON.equalsTypeAndSubtype(mimeType) && elementType.isAssignableFrom(JsonNode.class);
        }
    
        @Override
        public Flux<DataBuffer> encode(Publisher<? extends JsonNode> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
            return Flux.from(inputStream).map((JsonNode node) ->
                    encodeValue(node, bufferFactory, elementType, mimeType, hints));
        }
    
        @Override
        public DataBuffer encodeValue(JsonNode node, DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType, Map<String, Object> hints) {
            return bufferFactory.wrap(gzip(node.toString()));
        }
    
        private byte[] gzip(String value) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
                gzipOutputStream.write(value.getBytes());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return baos.toByteArray();
        }
    }
    

    那么你还必须实现一个HttpMessageWriter

    public class GzipHttpMessageWriter extends EncoderHttpMessageWriter {
    
        public GzipHttpMessageWriter() {
            super(new GzipEncoder());
        }
    
        @Override
        public Mono<Void> write(Publisher inputStream, ResolvableType elementType, MediaType mediaType, ReactiveHttpOutputMessage message, Map hints) {
            return super.write(inputStream, elementType, mediaType, updateContentEncoding(message), hints);
        }
    
        private ReactiveHttpOutputMessage updateContentEncoding(ReactiveHttpOutputMessage message) {
            message.getHeaders().add("Content-Encoding", "gzip");
            return message;
        }
    }
    

    现在创建您的WebClient,如下所示(我添加了窃听器以确认 gzip 工作正常)

    WebClient webclientGzip = WebClient.builder()
            .codecs(clientCodecConfigurer -> clientCodecConfigurer.customCodecs().register(new GzipHttpMessageWriter()))
            .clientConnector(new ReactorClientHttpConnector(HttpClient.create().wiretap(true)))
            .build();
    

    现在,当我发布带有以下内容的 JsonNode 主体时,我可以看到使用 gzip 编码的请求发出

    webclientGzip.post().uri(uri)
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_JSON)
                .body(Mono.just(body), JsonNode.class)
    

    【讨论】:

    • 非常感谢!在对我们的代码稍作修改后,它就可以工作了。
    猜你喜欢
    • 2019-12-25
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2011-07-01
    • 2022-01-25
    • 1970-01-01
    • 2019-11-28
    相关资源
    最近更新 更多