一、Zuul的路由功能
使用Spring初始化工具创建工程:
pom
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.liaoxiang.zuul</groupId>
<artifactId>user-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<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.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class UserZuulApplication {
public static void main(String[] args) {
SpringApplication.run(UserZuulApplication.class, args);
}
}
路由的几种配置
zuul:
routes:
user-service: #路由id,任意取
path: /user-service/** #映射路径
serviceId: user-service #指定服务id
zuul:
routes:
user-service: /user-service/** #服务id: 路由路径
默认的路由规则就是
服务名:服务名/**
,所以以上配置可以省略,当路径不想使用服务名称的时候就可以添加配置来改变默认的额规则:比如
zuul:
routes:
user-service: /user/** #服务id: 路由路径
配置路由前缀:localhost:10010/api/user/**
zuul:
prefix: /api #加前缀
retryable: true
Zuul中也集成了Ribbon和Hystrix,整个配置如下
server:
port: 10010
spring:
application:
name: api-gateway
zuul:
routes:
user-service: /user-service/**
user-consumer: /user-consumer/**
prefix: /api #加前缀
retryable: true
eureka:
client:
registry-fetch-interval-seconds: 5
service-url:
defaultZone: http://localhost:10086/eureka
ribbon:
ConnectTimeout: 250 # 连接超时时间(ms)
ReadTimeout: 2000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 6000 # 熔断超时时长:6000ms
浏览器访问:http://localhost:10010/api/user-consumer/user/findUsers?ids=1,2,3,4
二、Zuul过滤器
使用场景:请求鉴权、异常处理、服务调用时长统计等
ZuulFilter是过滤器的顶级父类,其中定义的4个最重要的方法
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter();// 来自IZuulFilter
Object run() throws ZuulException;// IZuulFilter
}
shouldFilter
:返回一个
Boolean
值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
run
:过滤器的具体业务逻辑。
filterType
:返回字符串,代表过滤器的类型。包含以下4种:
pre
:请求在被路由之前执行
route
:在路由请求时调用
post
:在route和errror过滤器之后调用
error
:处理请求时发生错误调用
filterOrder
:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
自定义过滤器,模拟鉴权
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 2;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
// 获取请求参数中的token
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
//当微服务需要头信息时,要转发头信息
String header = request.getHeader("Authorization");
if(header !=null && !"".equals(header)){
contxt.addZuulRequestHeader("Authorization", header);
}
// 获取参数
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)){
// 未登录
context.setResponseStatusCode(401);
// 不再继续路由
context.setSendZuulResponse(false);
}
return null;
}
}
测试,不带token参数
测试,带上token参数