#java #gzip #okhttp #websphere-liberty
#java #gzip #OkHttp #WebSphere-liberty
Вопрос:
Мы используем WebSphere Liberty 21.0.0.x и Java 11. У нас есть главный сервер, и у нас есть несколько микросервисов, которые тайно передают данные на главный сервер. Пользователи получат доступ к пользовательскому интерфейсу через URL-адрес основного сервера и ничего не узнают о микросервисах под обложками. Сегодня мы написали код на Java с использованием java-библиотек OkHttp для выполнения запросов к микросервису. Эти запросы могут быть запросами GET или POST. В любом типе запроса есть данные тела сообщения (в форме json), и они могут быть довольно большими … отсюда и необходимость сжатия. Обратные ответы также могут быть довольно большими. Я хочу, чтобы сжатие gzip было до микросервиса и обратно.
Я включил сжатие в WebSphere Liberty, выполнив шаги, описанные здесь: https://openliberty.io/blog/2020/04/22/http-response-compression.html Кульминационный момент заключается в добавлении некоторого xml в server.xml . Это довольно просто. Вот основной фрагмент из моего server.xml файл:
<httpEndpoint host="*" id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443">
<compression serverPreferredAlgorithm="gzip">
<types> application/*</types>
<types>-text/plain</types>
</compression>
</httpEndpoint>
Я понимаю, что это все, что мне нужно сделать на стороне сервера, и любая кодировка содержимого, с которой клиент обращается, будет учитываться сервером.
Вот клиентский код на java, в котором я пытаюсь опубликовать сообщение с использованием сжатия gzip:
private static final OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new CompressionInterceptor())
.readTimeout(5000, TimeUnit.MILLISECONDS)
.writeTimeout(10000, TimeUnit.MILLISECONDS)
.build();
// later in the code
RequestBody jsonRequestBody = RequestBody.create(data, MEDIA_TYPE_JSON);
Request request = new Request.Builder()
.url(urlString)
.addHeader("Accept", "application/json")
.post(jsonRequestBody)
.build();
Call call = client.newCall(request);
Response response = call.execute();
if (response.isSuccessful()) {
String responseString = response.body().string();
}
...
Вот код запроса GET:
String url = urlBuilder.build().toString();
Request request = new Request.Builder().url(url).addHeader("Accept", "application/json").build();
Call call = client.newCall(request);
Response response = call.execute();
if (response.isSuccessful()) {
String someResponse = response.body().string();
}
...
Вот класс перехватчика, который я настроил для создания экземпляра OkHttpClient:
public class CompressionInterceptor implements Interceptor {
private static final String CONTENT_ENCODING = "Content-Encoding";
private static final String GZIP = "gzip";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.body() == null || request.header(CONTENT_ENCODING) != null) {
return chain.proceed(request);
}
Request compressedRequest = request.newBuilder().header(CONTENT_ENCODING, GZIP)
.method(request.method(), gzip(request.body())).build();
return chain.proceed(compressedRequest);
}
private RequestBody gzip(final RequestBody body) {
return new RequestBody() {
@Override
public MediaType contentType() {
return body.contentType();
}
@Override
public long contentLength() {
return -1; // Allow any length
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
}
У меня есть пара вопросов.
a.) Я не уверен, что вышеприведенное действительно работает так, как задумано. Могу ли я сказать что-нибудь, кроме wire shark? Когда я тестирую с использованием REST-клиента, такого как Postman, я вижу, что в ответе сервера gzip является частью заголовков. Однако, со стороны кода, я не могу на 100% сказать, что он отправляет данные в сжатом виде.
б.) Я не уверен, что у меня система правильно настроена / закодирована для сжатия в обоих направлениях. т.е. я не уверен, что и запрос, и ответ действительно сжаты.
Комментарии:
1. Для (a) я лично обнаружил, что tcptunnel полезен в этих ситуациях. ( github.com/vakuum/tcptunnel ) В основном установите tcptunnel для прослушивания порта X и перенаправления на порт Y (который прослушивает сервер), и он будет печатать трафик между ними. Затем вам нужно изменить свой клиент, чтобы он подключался к порту X и выполнял запросы. Это покажет вам, правильно ли добавлены заголовки к запросу и ответу. Я не знаю о (b), но кто-то, более знакомый с функцией сжатия GZIP в Liberty, должен быть в состоянии помочь.
2. Конфигурация Liberty и код приложения, которые вы здесь разместили, выглядят правильно. Вы против использования Wireshark? Было бы довольно просто (с помощью Wireshark) проверить как a), так и b), выполнив поиск поля типа Content-encoded entity body (gzip) в запросах и ответах.
3. Я не против ни того, ни другого программного обеспечения. Я только что обнаружил, что анализаторы пакетов собирают так много трафика (даже когда вы пытаетесь захватить небольшое временное окно), что становится очень сложно. Достаточно справедливо, если это единственный и лучший способ.
4. Добавьте NetworkInterceptor в свое приложение, чтобы точно видеть, что отправляется по проводам.
5. @Юрий Шимке — Вы имеете в виду другой перехватчик OkHttp или фильтр Java? Можете ли вы предоставить некоторые подробности? Спасибо!