Перейти к основному содержимому

Изменение тела ответа в фильтре Zuul

· 3 мин. чтения

1. Обзор

В этом уроке мы рассмотрим пост-фильтр Netflix Zuul.

Netflix Zuul — это поставщик пограничных услуг, который находится между клиентом API и множеством микросервисов.

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

2. Зависимости

Мы собираемся работать с Zuul в среде Spring Cloud. Итак, давайте добавим следующее в раздел управления зависимостями нашего pom.xml:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
</dependencies>

Последнюю версию зависимостей Spring Cloud и spring-cloud-starter-netflix-zuul можно найти на Maven Central.

3. Создание пост-фильтра

Пост-фильтр — это обычный класс, который расширяет абстрактный класс ZuulFilter и имеет тип фильтра post :

public class ResponseLogFilter extends ZuulFilter {

@Override
public String filterType() {
return POST_TYPE;
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() throws ZuulException {
return null;
}
}

Обратите внимание, что мы вернули POST_TYPE в методе filterType() . Это то, что на самом деле отличает этот фильтр от других типов.

Еще один важный метод, на который следует обратить внимание, — это метод shouldFilter() . Здесь мы возвращаем true , так как хотим, чтобы фильтр запускался в цепочке фильтров.

В готовом к работе приложении мы можем внедрить эту конфигурацию для большей гибкости.

Давайте подробнее рассмотрим функцию run() , которая вызывается всякий раз, когда работает наш фильтр.

4. Изменение тела ответа

Как указывалось ранее, Zuul находится между микросервисами и их клиентами. Следовательно, он может получить доступ к телу ответа и при необходимости изменить его перед передачей вниз.

Например, мы можем прочитать тело ответа и записать его содержимое:

@Override
public Object run() throws ZuulException {

RequestContext context = RequestContext.getCurrentContext();
try (final InputStream responseDataStream = context.getResponseDataStream()) {

if(responseDataStream == null) {
logger.info("BODY: {}", "");
return null;
}

String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
logger.info("BODY: {}", responseData);

context.setResponseBody(responseData);
}
catch (Exception e) {
throw new ZuulException(e, INTERNAL_SERVER_ERROR.value(), e.getMessage());
}

return null;
}

Фрагмент выше показывает полную реализацию метода run() в ResponseLogFilter , который мы создали ранее. Во-первых, мы получили экземпляр RequestContext . И из этого контекста мы смогли получить данные ответа InputStream в конструкции try with resources.

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

Двигаясь вперед, мы читаем входной поток в строку , которую затем можем регистрировать.

Очень важно, что мы добавляем тело ответа обратно в контекст для обработки, используя context.setResponseBody(responseData). Если мы пропустим этот шаг, мы получим IOException следующего содержания: java.io.IOException: Попытка чтения в закрытом потоке .

5. Вывод

В заключение, пост-фильтры в Zuul дают разработчикам возможность что-то сделать с ответом службы перед его отправкой клиенту.

Однако мы должны быть осторожны, чтобы случайно не раскрыть конфиденциальную информацию, что может привести к взлому.

Более того, мы должны с осторожностью выполнять длительные задачи в рамках нашего пост-фильтра, так как это может значительно увеличить время отклика.

Как обычно, исходный код доступен на GitHub .