Spring WS запрос сжатия GZIP - PullRequest
0 голосов
/ 05 декабря 2018

Я создаю приложение Spring Boot, которое ведет себя как клиент для другого веб-сервиса.Использование WebServiceTemplate для отправки сообщений SOAP, и у меня есть случай, когда запрос достаточно велик, чтобы целевая служба требовала его сжатия gzip.Как я понимаю, обработка сжатых ответов выполняется по умолчанию на стороне клиента, но не для запросов, поскольку это не является стандартом.Я использую Java 8, Spring Boot 2.1 и Spring WS 3.0.3

Настройка заголовков MIME не помогает мне, так как это не приводит к сжатию полезной нагрузки, равно как и установка server.compression.enabled (наряду сразличные mime-типы) в свойствах приложения, и я знаю, что это не неисправный сервис на другом конце, потому что он работает с SoapUI.

Итак, мой вопрос - как я могу включить сжатие gzip для исходящих запросов?

1 Ответ

0 голосов
/ 07 декабря 2018

Решением, которое работало для нас, было создание перехватчика Http, который выполняет сжатие, и предоставление WebServiceTemplate нового HttpComponentMessageSender с этим перехватчиком.Вот как выглядит перехватчик:

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.entity.GzipCompressingEntity;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

import java.net.URI;
import java.net.URISyntaxException;

public class GzipHttpRequestInterceptor implements HttpRequestInterceptor {

    private final String targetHost;

    public GzipHttpRequestInterceptor(String targetUrl) throws URISyntaxException {
        this.targetHost = getDomainName(targetUrl);
    }

    private String getDomainName(String url) throws URISyntaxException {
        URI uri = new URI(url);
        String domain = uri.getHost() + ":" + uri.getPort();
        return domain.startsWith("www.") ? domain.substring(4) : domain;
    }

    @Override
    public void process(HttpRequest httpRequest, HttpContext httpContext) {
        final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) httpRequest;
        final HttpEntity entity = entityRequest.getEntity();
        if (entity != null) {
            final GzipCompressingEntity zippedEntity = new GzipCompressingEntity(entity);
            entityRequest.setEntity(zippedEntity);

            httpRequest.removeHeaders(HTTP.CONTENT_ENCODING);
            httpRequest.addHeader(zippedEntity.getContentEncoding());

            httpRequest.removeHeaders(HTTP.CONTENT_LEN);
            httpRequest.removeHeaders("Accept");

            httpRequest.removeHeaders(HTTP.TRANSFER_ENCODING);
            httpRequest.addHeader(HTTP.TRANSFER_ENCODING, HTTP.CHUNK_CODING);
            httpRequest.addHeader(HTTP.TARGET_HOST, targetHost);
        }
    }
}

В нашей веб-конфигурации мы собираем компоненты org.apache.http.protocol.HttpProcessor и org.springframework.ws.transport.http.HttpComponentsMessageSender:

    @Bean
    public HttpProcessor httpRequestCompressionProcessor(String url) throws URISyntaxException {
        return HttpProcessorBuilder.create()
                .add(new GzipHttpRequestInterceptor(url))
                .build();
    }

    @Bean
    public HttpComponentsMessageSender messageGzipSender(String url) throws URISyntaxException {
        return new HttpComponentsMessageSender(HttpClients.custom()
                .addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor())
                .setHttpProcessor(httpRequestCompressionProcessor(url))
                .build());
    }

И затем назначаем отправителя этого сообщения нашему WebServiceTemplate с использованием setMessageSender(messageGzipSender(url)

Полагаю, я не возражаю против комментариев к этому коду, если он может быть улучшен и все еще готов услышать, если есть более простой способ.

...