Spring Cloud Zuul服务网关
Spring Cloud Zuul服务网关
在微服务的架构中,服务网关就是一个介于客户端与服务端之间的中间层。在这种情况下,客户端只需要跟服务网关交互,无需调用具体的微服务接口。这样的好处在于,客户端可以降低复杂性;对于需要认证的服务,只需要在服务网关配置即可;同样也方便后期微服务的变更和重构,即微服务接口变更只需在服务网关调整配置即可,无需更改客户端代码。
Zuul是一款由Netflix开发的微服务网关开源软件,可以和其自家开发的Eureka,Ribbon和Hystrix配合使用,Spring Cloud对其进行了封装。
继续在原来的项目开发,开启两个Eureka集群,两个服务端。
接下来创建一个新项目Zuul-Gateway。
配置如下:
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.19.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 12580
spring:
application:
name: Zuul-Gateway
# 传统配置就是手动指定服务的转发地址,如在yml中配置:
#zuul:
# routes:
# api-a:
# path: /api-a/**
# url: http://localhost:8082
# 通过上面的配置,所有符合/api-a/**规则的访问都将被路由转发到http://localhost:8082/地址上,即当我们向服务网关访问http://localhost:12580/api-a/hello请求的时候,请求将被转发到http://localhost:8082/hello服务上
# 传统的配置方式不便之处在于需要知道服务的具体地址和端口号等信息,我们可以借助Eureka来实现通过服务名称配置路由。
# 配置基于服务名称的路由
eureka:
client:
register-with-eureka: true
fetch-registry: true
serviceUrl: # 指定Eureka服务端的地址,这里为上面定义的Eureka服务端地址
defaultZone: http://localhost:8080/eureka/,http://localhost:8081/eureka/
zuul:
routes:
api-a:
path: /api-b/**
serviceId: server-provider
api-b:
path: /api-c/**
serviceId: server-provider-two
# 本地跳转: Zuul网关除了支持将服务转发到各个微服务上之外,还支持将服务跳转到网关本身的服务上,配置:
# 访问 http://localhost:12580/gateway/api-e/zuul 会走本地方法
api-e:
path: /api-e/**
url: forward:/test
################################################
# 头部过滤 & 重定向
# 在使用Zuul网关的时候你可能会遇到Cookie丢失的情况,这是因为默认情况下Zuul会过滤掉HTTP请求头中的一些敏感信息,这些敏感信息通过下面的配置设定:
# sensitive-headers: Cookie,Set-Cookie,Authorization # 想关闭这个默认配置,通过设置全局参数为空来覆盖默认值
# 想关闭某个路由的HTTP请求头过滤,可以这样
# api-e:
# path: /api-e/**
# url: forward:/test
# sensitive-headers:
# add-host-header: true # 重定向
###############################################
# 配置简化
#zuul:
# routes:
# server-provider:
# path: /api-b/**
# server-provider-two:
# path: /api-c/**
# ignored-services: * 关闭所有默认路由配置规则 默认会用serviceId作为path
# 优先级问题:1./api-b/** 2./api-c/user/** 请求来了谁在前面就用谁
# 前缀配置
prefix: /gateway # 通过Zuul网关获取服务的时候,路径也得加上这个前缀,如http://localhost:12580/gateway/api-b/test/hello
###############################################
# 过滤器
# 4种过滤器处于不同的生命周期,所以其职责也各不相同:
#
# PRE:PRE过滤器用于将请求路径与配置的路由规则进行匹配,以找到需要转发的目标地址,并做一些前置加工,比如请求的校验等;
#
# ROUTING:ROUTING过滤器用于将外部请求转发到具体服务实例上去;
#
# POST:POST过滤器用于将微服务的响应信息返回到客户端,这个过程种可以对返回数据进行加工处理;
#
# ERROR:上述的过程发生异常后将调用ERROR过滤器。ERROR过滤器捕获到异常后需要将异常信息返回给客户端,所以最终还是会调用POST过滤器。
# Spring Cloud Zuul为各个生命周期阶段实现了一批过滤器:
# 生命周期 优先级 过滤器 功能描述
# pre -3 ServletDetectionFilter 标记处理Servlet的类型
# pre -2 Servlet30WrapperFilter 包装HttpServletRequest请求
# pre -1 FormBodyWrapperFilter 包装请求体
# route 1 DebugFilter 标记调试标志
# route 5 PreDecorationFilter 处理请求上下文供后续使用
# route 10 RibbonRoutingFilter serviceId请求转发
# route 100 SimpleHostRoutingFilter url请求转发
# route 500 SendForwardFilter forward请求转发
# post 0 SendErrorFilter 处理有错误的请求响应
# post 1000 SendResponseFilter 处理正常的请求响应
# 其中优先级数字越小,优先级越高。
# 关闭某个 过滤器:
# zuul:
# SendResponseFilter:
# post:
# disable:
# true
自定义过滤器:
/**
* @author chenqi
* @date 2019/7/9 14:44
*/
@Component
public class PreSendForwardFilter extends ZuulFilter {
// 对应Zuul生命周期的四个阶段:pre、post、route和error;
@Override
public String filterType() {
return "pre";
}
// 过滤器的优先级,数字越小,优先级越高;
@Override
public int filterOrder() {
return 1;
}
// 方法返回boolean类型,true时表示是否执行该过滤器的run方法,false则表示不执行;
@Override
public boolean shouldFilter() {
return true;
}
// 过滤器的过滤逻辑。
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String host = request.getRemoteHost();
String method = request.getMethod();
String uri = request.getRequestURI();
System.out.println("请求URI:" + uri);
System.out.println("HTTP Method:" + method);
System.out.println("请求IP:" + host);
return null;
}
}
测试类:
/**
* @author chenqi
* @date 2019/7/9 14:21
*/
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping("/zuul")
public String test() {
return "hello zuul";
}
}