1.前言
上一节:SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
Zuul 本身是一系列过滤器的集成,那么他当然也就提供了自定义过滤器的功能,Zuul 提供了四种过滤器:前置过滤器,路由过滤器,错误过滤器,简单过滤器。实现起来也非常简单,只需要编写一个类去实现 Zuul 提供的接口 - ZuulFilter。
2.准备
延用上一节的项目,并分别启动以下模块:
- 服务注册中心:wei-eureka-server,端口号:8090
- 服务提供者:wei-service-provider,端口号:8010、8011
- 服务消费者:wei-consumer-ribbon,端口号:8020
服务注册中心(http://localhost:8090/)查看服务,如下,注册成功:
首先,可以正常访问服务:http://localhost:8060/api/consumerGroup/demo/info?name=tester
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011
如果不能正常访问,可以看看上一节 SpringCloud进击 | 六浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
如上,准备工作完成。
3.进击
3.1.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.wei</groupId>
<artifactId>wei-gateway-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wei-gateway-zuul</name>
<description>Demo project for Spring Cloud Zuul</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.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-eureka-client</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>
<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>
3.2.application.yml 配置文件
文件与上一节相同,无需改造
server:
port: 8060 # 自定义程序启动端口
spring:
application:
name: wei-gateway-zuul # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
client:
service-url:
defaultZone: http://localhost:8090/eureka/ # 指定进行服务注册的地址
zuul:
routes: # 配置路由映射
wei-service-provider: /providerGroup/** # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**
consumerGroup: # 保证唯一
#url: http://localhost:8020/ # url绑定映射
serviceId: wei-consumer-ribbon # 给指定的服务做映射
path: /consumerGroup/** # path绑定映射。配置映射的路径,当前配置是将/wei-consumer-ribbon/**映射为/consumerGroup/**
prefix: /api
ribbon:
eureka:
enabled: false # 在eureka中禁用 ribbon 的负载均衡
wei-consumer-ribbon:
ribbon: # 给配置serviceId对应的服务指定ribbon负载均衡,从listOfServers配置的服务地址中分配服务,多个用半角逗号分隔
listOfServers: http://localhost:8010/, http://localhost:8011/
3.3.Zuul 过滤器
通过继承 ZuulFilter 抽象类,编写自定义 Filter。
package com.wei.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
@Component
public class WeiZuulFilter extends ZuulFilter {
/**
* 类型包含 pre、post、route、error
* pre:在路由代理之前执行
* route:代理的时候执行
* error:出现错的时候执行
* post:在route 或者是 error 执行完成后执行
*
* 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行
* 这里定义为pre,表示会在请求被路由之前执行
*
* @return 过滤器类型
*/
@Override
public String filterType() {
return "pre";
}
/**
* Zuul filter 为链式过滤器,多个filter按顺序执行,通过数字指定
* 数字越大,优先级越低
*
* @return 执行顺序
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否启用该过滤器
* 判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效
* 实际运用中我们可以利用该函数来指定过滤器的有效范围
*
* @return true:启用过滤器 / false:禁用过滤器
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体逻辑实现Demo
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("[ Demo For Zuul Filter ] Execute!");
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
System.out.println("[ Demo For Zuul Filter ] token parameter is empty!");
// 使用 Zuul 过滤此种场景的请求,不对其进行路由
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(401);
requestContext.setResponseBody("token is empty!");
} else {
System.out.println("[ Demo For Zuul Filter ] test success!");
}
return null;
}
}
3.4.启动类
文件与上一节相同,无需要改造
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* 注解@EnableZuulProxy,开启Zuul功能,自带熔断
*/
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class WeiGatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(WeiGatewayZuulApplication.class, args);
}
}
好了,到此,Zuul Filter 过滤器就已添加完成。其实只是增加并实现了一个自定义 ZuulFilter 类。
运行这个启动类。
4.测试
访问:http://localhost:8060/api/consumerGroup/demo/info?name=tester
浏览器输出:
token is empty!
后台日志打印:
前端看一看,请求返回结果状态是401。如此,说明 Zuul 过滤器已经在正常工作。
那我们把 token 参数加上:token=token_test
访问:http://localhost:8060/api/consumerGroup/demo/info?name=tester&token=token_test
浏览器打印:
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010
后台日志打印:
有木有,通过过滤器,Zuul 正确路由到了配置文件配置好的 加了前缀(/api) 映射(/consumerGroup)的 /demo/info 接口。
5.总结
上面的代码实现过程中,当通过继承 ZuulFilter 抽象类后,需要我们重写它的四个方法:
- filterType():过滤器的类型。它决定过滤器在请求的哪个生命周期中执行。其类型包含 pre、post、route、error。
- pre:在路由代理之前执行
- route:代理的时候执行
- error:出现错的时候执行
- post:在route 或者是 error 执行完成后执行
- filterOrder():过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。通过数字指定,数字越大,优先级越低。
- shouldFilter():判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。
- run():过滤器的具体逻辑。这里我们只是简单实现了一下,使用 Zuul 过滤入参没有 token 场景的请求,不对其进行路由。
官方参考文档:https://springcloud.cc/spring-cloud-netflix.html
下一节,请继续关注:SpringCloud进击 | 一深入:高可用的服务注册中心【Finchley版本】