一、路由器和过滤器(Zuul)介绍
1、微服务网关背景
不同的微服务一般有不同的网络地址,而外部的客户端可能需要调用多个服务的接口才能完成一个业务需求。如果客户端直接和微服务进行通信,会存在一下问题:
- 客户端会多次请求不同微服务,增加客户端的复杂性
- 存在跨域请求,在一定场景下处理相对复杂
- 认证复杂,每一个服务都需要独立认证
- 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通信,那么重构会难以实施
- 某些微服务可能使用了其他协议,直接访问有一定困难
这时可以借助微服务网关解决,微服务网管是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关,架构演变成:
这样客户端只需要和网关交互,不需直接调用特定微服务的接口。有利于监控,易于认证,减少客户端和各个微服务之间的交互次数。
2、Zuul简介
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
3、zuul的功能
- 验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
- 审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
- 动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
- 压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
- 负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
- 静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
- 多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
- Netflix公司还利用Zuul的功能通过金丝雀版本实现精确路由与压力测试。
二、代码实现测试
1、创建工程,如图结构:
其他Model工程的创建和上篇的SpringCloud——断路器(Hystrix)相同,请参考实现工程的创建及业务代码的实现。
地址:https://blog.csdn.net/typ1805/article/details/82682504
2、创建service-zuul工程
pom.xml文件的依赖,如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.demo.zuul</groupId>
<artifactId>service-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>service-zuul</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.example.demo</groupId>
<artifactId>springcloud-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml配置文件,如下:
server:
port: 8085
eureka:
client:
service-url:
defaultZone: http://localhost:8081/eureka/
spring:
application:
name: service-zuul
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
zuul:
host:
connect-timeout-millis: 10000
socket-timeout-millis: 60000
routes:
api-a:
path: /api-a/**
serviceId: service-zuul-ribbon
api-b:
path: /api-b/**
serviceId: service-zuul-feign
指定服务注册中心的地址为http://localhost:8081/eureka/,服务的端口为8085,服务名为service-zuul。以/api-a/ 开头的请求都转发给service-zuul-ribbon服务,以/api-b/开头的请求都转发给service-zuul-feign服务,serviceId指定的对应服务的spring.application.name名称。
启动类添加注解@EnableZuulProxy,开启zuul功能,代码如下:
package com.example.demo.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableEurekaClient
@EnableZuulProxy
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceZuulApplication.class, args);
}
}
启动工程,浏览器访问:http://localhost:8085/api-a/test?name=张三 ,浏览器显示:
张三---------------8082
浏览器访问:http://localhost:8085/api-b/test?name=张三 ,浏览器显示:
张三---------------8082
3、实现过滤器
在service-zuul中创建一个过滤器类myFilter并实现ZuulFilter类,代码如下:
package com.example.demo.zuul.config;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 路径:com.example.demo.zuul.config
* 类名:
* 功能:过滤器
* 备注:
* 创建人:typ
* 创建时间:2018/9/13 14:12
* 修改人:
* 修改备注:
* 修改时间:
*/
@Component
public class MyFilter extends ZuulFilter {
private static final Logger log = LoggerFactory.getLogger(MyFilter.class);
/**
* 方法名:filterType
* 功能:返回一个字符串代表过滤器的类型
* 描述:
* pre:路由之前
* routing:路由之时
* post: 路由之后
* error:发送错误调用
* 创建人:typ
* 创建时间:2018/9/13 14:23
* 修改人:
* 修改描述:
* 修改时间:
*/
@Override
public String filterType() {
return "pre";
}
/**
* 方法名:filterOrder
* 功能:过滤的顺序
* 描述:
* 创建人:typ
* 创建时间:2018/9/13 14:24
* 修改人:
* 修改描述:
* 修改时间:
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 方法名:shouldFilter
* 功能:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
* 描述:
* 创建人:typ
* 创建时间:2018/9/13 14:25
* 修改人:
* 修改描述:
* 修改时间:
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 方法名:run
* 功能:过滤器的具体逻辑。
* 描述:
* 创建人:typ
* 创建时间:2018/9/13 14:25
* 修改人:
* 修改描述:
* 修改时间:
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
log.info("method:{}, url:{}",request.getMethod(),request.getRequestURL());
Object token = request.getParameter("token");
if(token == null){
log.info("token is empty");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("token is empty");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
log.info("ok");
return null;
}
}
Zuul的过滤器之间没有直接的相互通信,他们之间通过一个RequestContext的静态类来进行数据传递的。RequestContext类中有ThreadLocal变量来记录每个Request所需要传递的数据。
Zuul的过滤器是由Groovy写成,这些过滤器文件被放在Zuul Server上的特定目录下面,Zuul会定期轮询这些目录,修改过的过滤器会动态的加载到Zuul Server中以便过滤请求使用。
下面有几种标准的过滤器类型:
- PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
- ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
- ERROR:在其他阶段发生错误时执行该过滤器。
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期。
启动工程,访问:http://localhost:8085/api-a/test?name=张三 ,浏览器显示:
token is empty
访问 http://localhost:8085/api-a/test?name=张三&token=11 ,浏览器显示:
张三---------------8082
源码下载:https://download.csdn.net/download/typ1805/10664599
官网文档地址:https://springcloud.cc/spring-cloud-dalston.html
欢迎关注