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 .