简述
不同的微服务一般会有不同的服务地址,客户端在访问这些地址的时候需要记录几十甚至几百个地址,这对于客户端来说过于复杂和难以维护。
这样存在的问题有:客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度。而且这样的机制会增加身份认证的难度,每个微服务需要独立认证。
微服务网关
微服务网关就应运而生,微服务网关介于客户端与服务器之间的中间层,它是一个服务器,是系统对外的唯一入口。所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可。
Zuul网关
Zuul网关是是Netflflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件的核心是一系列的过滤器。这些过滤器可以完成:
动态路由:动态将请求路由到不同后端集群
压力测试:逐渐增加指向集群的流量,以了解性能
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
静态响应处理:边缘位置进行响应,避免转发到内部集群
身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。Spring Cloud对Zuul进行了整合和增强。
zuul的底层基于Servlet,本质上就是一系列的filter过滤器。
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去手动实现请求匹配,这样做显然就不合理。
Zuul支持与Eureka整合开发,根据ServiceID自动的从注册中心中获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加或移除服务实例的时候不用修改Zuul的路由配置。
我们首先要添加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 | 在其他阶段发生错误时执行该过滤器。 |
我们只需自定义一个filter类并继承ZuulFilter重写四个方法即可定义一个zuul过滤器类
zuul提供一个RequstContext上下文对象,它内部采用ThreadLocal保存每个请求的一些信息,包括请求路由、错误信息、HttpServletRequest、HttpServletResponse,这使得一些操作是十分可靠的,它还扩展了ConcurrentHashMap,目的是为了在处理过程中保存任何形式的信息
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;
}
}
zuul网关拦截器类 身份验证简单实现