简述
不同的微服务一般会有不同的服务地址,客户端在访问这些地址的时候需要记录几十甚至几百个地址,这对于客户端来说过于复杂和难以维护。
这样存在的问题有:客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度。而且这样的机制会增加身份认证的难度,每个微服务需要独立认证。
微服务网关
微服务网关就应运而生,微服务网关介于客户端与服务器之间的中间层,它是一个服务器,是系统对外的唯一入口。所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可。
Zuul网关
Zuul网关是是Netflflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件的核心是一系列的过滤器。这些过滤器可以完成:
动态路由:动态将请求路由到不同后端集群
压力测试:逐渐增加指向集群的流量,以了解性能
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
静态响应处理:边缘位置进行响应,避免转发到内部集群
身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。Spring Cloud对Zuul进行了整合和增强。
zuul的基本使用
首先要清楚的是zuul是一台服务器,我们要在项目中创建一个新的模组
引入zuul的相关依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
在springboot启动类上加入zuul的支持注解
至此zuul的准备工作已经完成
zuul基础路由配置
这里对路由的理解就是根据请求URL,将请求分配到对应的处理程序。在微服务体系中,Zuul负责接收所有的请求。根据不同的URL匹配规则,将不同的请求转发到不同的微服务处理。
我们在项目的yml文件中可以配置zuul的路由:
#路由配置
zuul:
routes:
product-server: #路由的id
path: /product-service/** #配置映射路径
url: http://127.0.0.1:9001 #映射路径的实际微服务url地址
面向服务的路由配置
微服务一般是由几十、上百个服务组成,对于一个URL请求,最终会确认一个服务实例进行处理。如果对每个服务实例手动指定一个唯一访问地址,然后根据URL去手动实现请求匹配,这样做显然就不合理。
我们首先要添加eureka的依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
然后开启eureka的服务发现:
我们还需要配置eureka
eureka:
client:
serviceUrl:
defaultZone: http://localhost:9000/eureka/
registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
instance:
preferIpAddress: true
ip-address: 127.0.0.1
此时我们的zuul基础路由配置中的url就可以不用写了,因为此时的服务地址是从eureka中获取的
我们只需配置serviceId即可
zuul:
routes:
product-service: # 这里是路由id,随意写
path: /product-service/** # 这里是映射路径
# url: http://127.0.0.1:9001 # 映射路径对应的实际url地址
serviceId: service-product #整合eureka后会从eureka中获取服务地址
sensitiveHeaders: #默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取 消默认的黑名单,如果设置了具体的头信息则不会传到下游服务
配置的简化
如果路由的id和service的id一致的话,我们可以只写这么一行配置映射路径
zuul:
routes:
#product-service: # 这里是路由id,随意写
# path: /product-service/** # 这里是映射路径
# # url: http://127.0.0.1:9001 # 映射路径对应的实际url地址
# serviceId: service-product #整合eureka后会从eureka中获取服务地址
# sensitiveHeaders: #默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取 消默认的黑名单,如果设置了具体的头信息则不会传到下游服务
service-product: /product-service/**
Zuul网关加入之后的架构图
Zuul网关过滤器
zuul的路由功能实现了统一处理外部请求的功能,负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。
zuul还提供过滤器功能,负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
ZuulFilter有四种类型:
PRE
|
这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请
求的微服务、记录调试信息等。
|
ROUTING
|
这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用
Apache HttpClient或Netfifilx Ribbon请求微服务。
|
POST
|
这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP
Header、收集统计信息和指标、将响应从微服务发送给客户端等。
|
ERROR
|
在其他阶段发生错误时执行该过滤器。
|
package hjj.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * 自定义的zuul过滤器 */ @Component public class LoginFilter extends ZuulFilter { //定义过滤器类型 pre routing post error @Override public String filterType() { return "pre"; } //指定过滤器的执行顺序 返回值越小执行顺序越高 @Override public int filterOrder() { return 1; } //当前过滤器是否生效 true使用 false不使用 @Override public boolean shouldFilter() { return true; } //执行过滤器中的业务逻辑 身份认证,所有的请求都需要携带一个参数:access-token @Override public Object run() throws ZuulException { //获取上下文对象 RequestContext ctx = RequestContext.getCurrentContext(); //获取request请求 HttpServletRequest request = ctx.getRequest(); //获取request参数 String token = request.getParameter("access-token"); //获取token并进行判断 if(token == null){ //拦截请求,认证失败 ctx.setSendZuulResponse(false);//拦截请求 ctx.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);//返回错误码 } System.out.println("执行了过滤器"); return null; } }