Статьи

Zuul 2 — образец фильтра

Zuul 2 наконец-то был открыт . Впервые я услышал о Zuul 2 во время выступления Майки Коэн весной 2016 года, и я рад, что наконец-то можно поиграть с ним.

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

  • Маршрутизация основана на различных критериях — URI, заголовки и т. Д.
  • Мониторинг службы здоровья
  • Балансировка нагрузки и регулирование запросов к исходным серверам
  • Безопасность
  • Канарское тестирование

Моя цель в этом посте проста — написать фильтр Zuul2, который может удалить префикс пути и отправить запрос в нисходящий сервис и обратно.

Фильтры Zuul2 — это механизм, с помощью которого настраивается Zuul. Скажем, если клиент отправляет запрос на вызов / passthrough / someapi, то я хочу, чтобы уровень Zuul 2 перенаправил запрос в нисходящий сервис, используя / someapi uri. Фильтры Zuul2, как правило, упакованы в виде файлов groovy, динамически загружаются (и потенциально обновляются) и применяются. Мой пример здесь будет немного другим, хотя мои фильтры написаны на Java, и мне пришлось обойти механизм загрузки, встроенный в Zuul.

Может быть проще просто следовать коду, который доступен в моем репозитории github здесь — https://github.com/bijukunjummen/boot2-load-demo/tree/master/applications/zuul2-sample, он упакован в набор образцов, которые обеспечивают аналогичную функциональность. Код основан на образцах Zuul 2, доступных здесь .

Вот так выглядит мой фильтр:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import com.netflix.zuul.context.SessionContext;
import com.netflix.zuul.filters.http.HttpInboundSyncFilter;
import com.netflix.zuul.message.http.HttpRequestMessage;
 
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class StripPrefixFilter extends HttpInboundSyncFilter {
    private final List<String> prefixPatterns;
 
    public StripPrefixFilter(List<String> prefixPatterns) {
        this.prefixPatterns = prefixPatterns;
    }
 
    @Override
    public HttpRequestMessage apply(HttpRequestMessage input) {
        SessionContext context = input.getContext();
        String path = input.getPath();
        String[] parts = path.split("/");
        if (parts.length > 0) {
            String targetPath = Arrays.stream(parts)
                    .skip(1).collect(Collectors.joining("/"));
            context.set("overrideURI", targetPath);
        }
        return input;
    }
 
    @Override
    public int filterOrder() {
        return 501;
    }
 
    @Override
    public boolean shouldFilter(HttpRequestMessage msg) {
        for (String target: prefixPatterns) {
            if (msg.getPath().matches(target)) {
                return true;
            }
        }
        return false;
    }
}

Он расширяет «HttpInboundSyncFilter», это фильтры, которые обрабатывают запросы, поступающие на исходные серверы. Как вы можете себе представить, существует «HttpOutboundSyncFilter», который перехватывает исходящие вызовы с исходных серверов. Существует аналог «HttpInboundFilter» и «HttpOutboundFilter» для этих фильтров «синхронизации», они возвращают наблюдаемый тип RxJava .

В моей реализации фильтра есть волшебная строка «overrideUri». Если вам интересно, как я обнаружил, что это переопределение URI, это сканирование через кодовую базу Zuul2. В Netflix, скорее всего, используется множество внутренних фильтров, которые еще не выпущены для общего потребления.

С этим фильтром я обошел функцию загрузки динамических скриптов Groovy в Zuul2, явно зарегистрировав свой пользовательский фильтр с помощью этого компонента:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import com.netflix.zuul.filters.FilterRegistry;
import com.netflix.zuul.filters.ZuulFilter;
 
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
 
public class FiltersRegisteringService {
 
    private final List<ZuulFilter> filters;
    private final FilterRegistry filterRegistry;
 
    @Inject
    public FiltersRegisteringService(FilterRegistry filterRegistry, Set<ZuulFilter> filters) {
        this.filters = new ArrayList<>(filters);
        this.filterRegistry = filterRegistry;
    }
 
    public List<ZuulFilter> getFilters() {
        return filters;
    }
 
    @PostConstruct
    public void initialize() {
        for (ZuulFilter filter: filters) {
            this.filterRegistry.put(filter.filterName(), filter);
        }
    }
}

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

После запуска образца Zuul2 с этим настраиваемым фильтром поведение заключается в том, что любой запрос к / passthrough / messages направляется в нисходящую систему после прекращения действия префикса «/ passthrough». Инструкции по запуску приложения Zuul 2 являются частью README репо .

На этом мы завершаем краткое введение в написание собственного фильтра Zuul2, я надеюсь, что этого достаточно, чтобы оценить Zuul 2.

Смотреть оригинальную статью здесь: Zuul 2 — Sample filter

Мнения, высказанные участниками Java Code Geeks, являются их собственными.