在本教程中,我们将学习如何将Spring Cloud Zuul代理用作API网关,这是微服务架构的重要组成部分。抽丝剥茧 细说架构那些事——【优锐课】
上篇文章说到,微服务系列详解-Part4:使用Netflix Hystrix的Spring Cloud断路器
在微服务架构中,可能有许多API服务和与API通讯的UI组件很少。到目前为止,许多基于微服务的应用程序仍使用整体的UI作为单个模块构建的整体式前端。您可能会选择使用微前端,在该微前端中,UI也被分解为与API通讯以获取相关数据的多个微服务。我们可以提供一个统一的代理接口,该接口将基于URL模式将调用委派给各种微服务,而不是让UI知道我们所有的微服务详细信息。在本文中,我们将学习如何使用Spring Cloud Zuul代理创建API网关。
在这篇文章中,我们将学习:
• 为什么我们需要一个API网关?
• 使用Spring Cloud Zuul代理实现API网关
• 使用Zuul过滤器解决跨领域关注点
API网关(也称为边缘服务)为一组微服务提供统一的接口,因此客户端无需了解微服务内部结构的所有详细信息。但是,在微服务体系结构中使用API网关模式有一些优缺点。
优点:
• 为客户端提供更轻松的界面。
• 可用于防止将内部微服务结构暴露给客户端。
• 允许重构微服务,而无需强制客户端重构使用逻辑。
• 可以集中解决跨部门的问题,例如安全性,监视,速率限制等。
缺点:
• 如果未采取适当措施使其高度可用,则可能会成为单点故障。
• 各种微服务API的知识可能会渗入API网关。
Spring Cloud提供类似于Nginx的Zuul代理,可用于创建API网关。
让我们创建一个前端UI模块“ shoppingcart-ui”作为Spring Boot应用程序,该应用程序还充当Zuul代理。使用Web,Config Client,Eureka Discovery,Zuul启动器创建一个SpringBoot项目,并使用@EnableZuulProxy注释主入口点类。
<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
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中注册的服务ID为“ service-id”的服务。
例如,从UI应用程序中,如果我们向http:// localhost:8080/catalog-service/products发出请求,则它将在Service Registry中查找ServiceID“ catalog-service”,并将带有URL/products的请求发送到以下其中一个 可用的目录服务实例。
为此,我们需要在Eureka Service Registry中注册“ shoppingcart-ui”。
bootstrap.properties
spring.application.name=shoppingcart-ui
server.port=8080
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
现在,通过这种配置,我们可以使用jQuery从目录服务中获取产品信息,如下所示:
$.ajax({
url: '/catalog-service/products'
})
.done(function(data) {
this.products = data;
}.bind(this));
在这里,从UI应用程序中,我们正在调用http://localhost:8080/catalog-service/products。假设目录服务已使用ServiceID"catalog-service"注册并在端口8181上运行,则此请求将转发到http://host:8181/products。但是,UI完全不知道实际的目录服务在哪里运行以及其主机名,端口号等。
我们还可以为URL使用通用前缀,例如"/api,"我们希望Zuul通过设置zuul.prefix属性来为其代理。
zuul.prefix=/api
现在,从用户界面,我们可以在http://localhost:8080/api/catalog-service/products上请求获取产品。默认情况下,Zuul将删除前缀并转发请求。
您还可以如下自定义服务的路径映射:
zuul.routes.catalogservice.path=/catalog/
zuul.routes.catalogservice.serviceId=catalog-service
通过此配置,您可以使用URL http://localhost:8080/api/catalog/products,该URL将通过serviceId catalog-service转发到该服务。
默认情况下,所有在Eureka Server中注册的服务都将公开。您可以使用zuul.ignored-services属性来禁用此行为,并仅公开显式配置的服务。
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服务来实现一些跨领域的问题,例如安全性,速率限制等。一个常见的用例是将Authentication标头转发到所有下游服务。
通常在微服务中,我们将使用OAuth服务进行身份验证和授权。客户端通过身份验证后,OAuth服务将生成一个令牌,该令牌应包含在对其他微服务的请求中,因此无需分别为每个服务都对客户端进行身份验证。我们可以使用Zuul过滤器来实现这样的功能。
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;
}
}
我们使用RequestContext.addZuulRequestHeader()将AUTH_HEADER添加为请求标头,该标头将转发到下游服务。我们需要将其注册为Spring bean。
@Bean
AuthHeaderFilter authHeaderFilter() {
return new AuthHeaderFilter();
}
感谢阅读!下篇继续:微服务系列详解- Part 6:使用Spring Cloud Sleuth和Zipkin进行分布式跟踪
另外还有一些资源分享给各位,需要的可以免费领取~