Статьи

MicroServices. Часть 5. Spring Cloud Zuul Proxy в качестве шлюза API

В архитектуре микросервисов может быть несколько служб API и несколько компонентов пользовательского интерфейса, которые взаимодействуют с API. На сегодняшний день многие приложения на основе микросервисов по-прежнему используют монолитные интерфейсы, в которых весь пользовательский интерфейс построен как единый модуль. Вы можете выбрать микро-интерфейсы, в которых пользовательский интерфейс также разбит на несколько микросервисов, взаимодействующих с API для получения соответствующих данных. Вместо того чтобы сообщать UI обо всех деталях наших микросервисов, мы можем предоставить унифицированный прокси-интерфейс, который будет делегировать вызовы различным микросервисам на основе шаблона URL. В этом посте мы узнаем, как создать API-шлюз с помощью Spring Cloud Zuul Proxy .

Микроуслуги с использованием Spring Boot и Spring Cloud

В этом посте мы собираемся узнать:

  • Зачем нам нужен API Gateway?
  • Реализация API-шлюза с использованием Spring Cloud Zuul Proxy
  • Использование фильтров Zuul для сквозных задач

Зачем нам нужен API Gateway?

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

Плюсы:

  • Обеспечивает более простой интерфейс для клиентов
  • Может использоваться для предотвращения раскрытия внутренней структуры микросервисов клиентам
  • Позволяет проводить рефакторинг микросервисов, не принуждая клиентов к рефакторизации логики потребления
  • Может централизовать сквозные проблемы, такие как безопасность, мониторинг, ограничение скорости и т. Д.

Минусы:

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

Реализация API-шлюза с использованием Spring Cloud Zuul Proxy

Spring Cloud предоставляет прокси Zuul, похожий на Nginx , который можно использовать для создания API Gateway.

Давайте создадим интерфейсный модуль пользовательского интерфейса «shoppingcart-ui» как приложение SpringBoot, которое также действует как прокси Zuul. Создайте проект SpringBoot с помощью Web , клиента конфигурации , Eureka Discovery , Zuul для запуска и аннотируйте основной класс точки входа с помощью @EnableZuulProxy .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

ShoppingcartUiApplication.java

01
02
03
04
05
06
07
08
09
10
11
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
 
@EnableZuulProxy
@SpringBootApplication
public class ShoppingcartUiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShoppingcartUiApplication.class, args);
    }
}

Поскольку мы также используем Eureka Discovery, запросы от прокси-сервера с шаблонами URL / service-id / ** будут перенаправляться на службу, зарегистрированную на Eureka Server с идентификатором службы «service-id» .

Например, из приложения пользовательского интерфейса, если мы сделаем запрос к http: // localhost: 8080 / catalog-service / products, тогда оно будет искать в Service Registry для ServiceID «catalog-service» и отправлять запрос с URL / products на один доступных экземпляров службы каталогов.

Чтобы это произошло, нам нужно зарегистрировать «shoppingcart-ui» в сервисном реестре Eureka.

bootstrap.properties

1
2
3
spring.application.name=shoppingcart-ui
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

С этой конфигурацией теперь мы можем получать информацию о продукте из каталога-сервиса, используя jQuery следующим образом:

1
2
3
4
5
6
$.ajax({
    url: '/catalog-service/products'
})
.done(function(data) {
    this.products = data;
}.bind(this));

Здесь из нашего пользовательского интерфейса мы звоним по адресу http: // localhost: 8080 / catalog-service / products. Предполагая, что служба каталогов зарегистрирована с ServiceID «catalog-service» и работает через порт 8181, этот запрос будет перенаправлен на http: // host: 8181 / products. Но пользовательский интерфейс совершенно не знает, где работает фактическая служба каталогов, номер порта его имени хоста и т. Д.

Мы также можем использовать общий префикс для URL-адресов, например «/ api» , для которого мы хотим, чтобы Zuul использовал прокси, установив свойство zuul.prefix .

1
zuul.prefix=/api

Теперь из пользовательского интерфейса мы можем сделать запрос на выборку продуктов по адресу http: // localhost: 8080 / api / catalog-service / products. По умолчанию Zuul удалит префикс и отправит запрос.

Вы также можете настроить отображение пути службы следующим образом:

1
2
zuul.routes.catalogservice.path=/catalog/**
zuul.routes.catalogservice.serviceId=catalog-service

В этой конфигурации вы можете использовать URL http: // localhost: 8080 / api / catalog / products, который будет перенаправлен в сервис с помощью serviceId catalog-service.

По умолчанию все сервисы, зарегистрированные на Eureka Server, будут доступны. Вы можете использовать свойство zuul.ignored-services, чтобы отключить это поведение и предоставлять только явно настроенные службы.

1
2
3
4
5
6
7
zuul.ignored-services=*
 
zuul.routes.catalogservice.path=/catalog/**
zuul.routes.catalogservice.serviceId=catalog-service
 
zuul.routes.orderservice.path=/orders/**
zuul.routes.orderservice.serviceId=order-service

При такой конфигурации только служба каталогов, служба заказов предоставляется через прокси Zuul, но не сервис инвентаризации .

Использование фильтров Zuul для сквозных задач

Поскольку Zuul выступает в качестве прокси-сервера для всех наших микросервисов, мы можем использовать сервис Zuul для реализации некоторых сквозных задач, таких как безопасность, ограничение скорости и т. Д. Одним из распространенных вариантов использования является пересылка заголовков аутентификации всем нисходящим службам.

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

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
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
 
public class AuthHeaderFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
 
    @Override
    public int filterOrder() {
        return 0;
    }
 
    @Override
    public boolean shouldFilter() {
        return true;
    }
 
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
 
        if (request.getAttribute("AUTH_HEADER") == null) {
            //generate or get AUTH_TOKEN, ex from Spring Session repository
            String sessionId = UUID.randomUUID().toString();
             
            ctx.addZuulRequestHeader("AUTH_HEADER", sessionId);
        }
        return null;
    }
}

Мы добавляем AUTH_HEADER в качестве заголовка запроса, используя RequestContext.addZuulRequestHeader (), который будет перенаправлен в нисходящие сервисы. Нам нужно зарегистрировать его как бин Spring.

1
2
3
4
@Bean
AuthHeaderFilter authHeaderFilter() {
    return new AuthHeaderFilter();
}

Вы можете найти исходный код этой статьи по адресу https://github.com/sivaprasadreddy/spring-boot-microservices-series

Опубликовано на Java Code Geeks с разрешения Сивы Редди, партнера нашей программы JCG . См. Оригинальную статью здесь: MicroServices. Часть 5. Spring Cloud Zuul Proxy в качестве шлюза API.

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