«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 и имеет тип фильтра поста:
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.