Spring Cloud 入门 之 Zuul 篇(五)
原文地址:Spring Cloud 入门 之 Zuul 篇(五)
博客地址:http://www.extlight.com
一、前言
随着业务的扩展,微服务会不对增加,相应的其对外开放的 API 接口也势必增多,这不利于前端的调用以及不同场景下数据的返回,因此,我们通常都需要设计一个 API 网关作为一个统一的 API 入口,来组合一个或多个内部 API。
二、简单介绍
2.1 API 网关使用场景
黑白名单: 实现通过 IP 地址控制请求的访问
日志:实现访问日志的记录,进而实现日志分析,处理性能指标等
协议适配:实现通信协议的校验、适配转换的功能
身份认证:对请求进行身份认证
计流限流:可以设计限流规则,记录访问流量
路由:将请求进行内部(服务)转发
2.2 API 网关的实现
业界常用的 API 网关有很多方式,如:Spring Cloud Zuul、 Nginx、Tyk、Kong。本篇介绍的对象正是 Spring Cloud Zuul。
Zuul 是 Netflix 公司开源的一个 API 网关组件,提供了认证、鉴权、限流、动态路由、监控、弹性、安全、负载均衡、协助单点压测等边缘服务的框架。
Spring Cloud Zuul 是基于 Netflix Zuul 的微服务路由和过滤器的解决方案,也用于实现 API 网关。其中,路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入门的基础。而过滤功能是负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
Spring Cloud Zuul 和 Eureka 进行整合时,Zuul 将自身注册到 Eureka 服务中,同时从 Eureka 中获取其他微服务信息,以便请求可以准确的通过 Zuul 转发到具体微服务上。
三、实战演练
本次测试案例基于之前发表的文章中介绍的案例进行演示,不清楚的读者请先转移至 《Spring Cloud 入门 之 Hystrix 篇(四)》 进行浏览。
当前的项目列表如下:
| 服务实例 | 端口 | 描述 |
|---|---|---|
| common-api | - | 公用的 api,如:实体类 |
| eureka-server | 9000 | 注册中心(Eureka 服务端) |
| goods-server | 8081 | 商品服务(Eureka 客户端) |
| goods-server-02 | 8082 | 商品服务(Eureka 客户端) |
| goods-server-03 | 8083 | 商品服务(Eureka 客户端) |
| order-server | 8100 | 订单服务(Eureka 客户端) |
创建一个为名 gateway-server 的 Spring Boot 项目。
3.1 添加依赖
<!-- eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- zuul 网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
3.2 配置文件
server:
port: 9600
spring:
application:
name: gateway
eureka:
instance:
instance-id: gateway-9600
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:9000/eureka/ # 注册中心访问地址
3.3 启动 Zuul
在启动类上添加 @EnableZuulProxy 注解:
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
启动上边的所有项目,打开 Postman 请求订单下单接口,如下图:

图中,我们首先不经过网关直接访问 order-server 项目请求地址:http://localhost:8100/order/place
之后再修改成访问 gateway-server 项目的请求地址:http://localhost:9600/order/order/place
最终,响应结果都一样。
提示:http://localhost:9600/order/order/place 中第一个 order 表示的是注册在 Eureka 上的订单服务名称。
3.4 zuul 常用配置
修改路由:
zuul:
sensitive-headers: # 全局忽略敏感头,即允许接收 cookie 等请求头信息
routes:
extlight: # 任意名字,保证唯一即可
path: /extlight/** # 自定义,真正用到的请求地址
service-id: ORDER # 路由到的目标服务名称
将订单服务的路由名称改成 extlight。
使用 Postman 请求下单接口,运行结果:

请求成功。
禁用路由:
zuul:
ignored-patterns:
- /order/order/**
http://localhost:9600/order/order/place 无法被正常路由到订单服务,响应返回 404。
路由加前缀:
zuul:
prefix: /api
所有请求中的 path 需要添加 api 前缀。如: http://localhost:9600/extlight/order/place 需要改成 http://localhost:9600/api/extlight/order/place。
设置敏感头:
zuul:
sensitive-headers: # 设置全局敏感头,如果为空,表示接收所有敏感头信息
或
zuul:
routes:
extlight: # 任意名字,保证唯一即可
path: /extlight/** # 自定义,真正用到的请求地址
service-id: ORDER # 路由到的目标服务名称
sensitive-headers: # 针对 /extlight/ 的请求设置敏感头信息
四、Zuul 自定义过滤器
Zuul 的核心技术就是过滤器,该框架提供了 ZuulFilter 接口让开发者可以自定义过滤规则。
我们以身份检验为例,自定义 ZuulFilter 过滤器实现该功能。
4.1 创建用户服务
新建名为 user-server 的项目。
添加依赖:
<!-- common api -->
<dependency>
<groupId>com.extlight.springcloud</groupId>
<artifactId>common-api</artifactId>
<version>${parent-version}</version>
</dependency>
<!-- springmvc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml:
server:
port: 8200
spring:
application:
name: USER
eureka:
instance:
instance-id: user-api-8200
prefer-ip-address: true # 访问路径可以显示 IP
client:
service-url:
defaultZone: http://localhost:9000/eureka/ # 注册中心访问地址
登录接口:
@RestController
@RequestMapping("/user")
public class LoginController {
@PostMapping("/login")
public Result login(String username, String password, HttpServletResponse response) {
if ("admin".equals(username) && "admin".equals(password)) {
// 模拟生成 token,实际开发中 token 应存放在数据库或缓存中
String token = "123456";
Cookie cookie = new Cookie("token", token);
cookie.setPath("/");
cookie.setMaxAge(60 * 10);
response.addCookie(cookie);
return Result.success();
}
return Result.fail(401, "账号或密码错误");
}
}
user-server 启动类:
@EnableEurekaClient
@SpringBootApplication
public class UserServerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServerApplication.class, args);
}
}
4.2 创建 ZuulFilter 过滤器
在 gateway-server 项目中,新建一个过滤器,需要继承 ZuulFilter 类:
@Component
public class AuthenticationFilter extends ZuulFilter {
/**
* 是否开启过滤
*/
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
boolean flag = request.getRequestURI().contains("/login");
// 如果是登录请求不进行过滤
if (flag) {
System.out.println("========不执行 zuul 过滤方法=======");
} else {
System.out.println("========执行 zuul 过滤方法=======");
}
return !flag;
}
/**
* 过滤器执行内容
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
// 此处模拟获取数据库或缓存中的 token
String dbToken = "123456";
// 此处简单检验 token
if (token == null || "".equals(token) || !dbToken.equals(token)) {
context.setSendZuulResponse(false);
context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
/**
* 过滤器类型
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤器执行顺序
*/
@Override
public int filterOrder() {
return 0;
}
}
其中,filterType 有 4 种类型:
pre: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
routing:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。
post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
error:在其他阶段发生错误时执行该过滤器。
其过滤顺序如下图:

4.3 测试过滤器
运行所有项目,测试操作步骤如下:
请求用户服务的登录接口(http://localhost:9600/user/user/login),请求不执行 zuul 过滤方法,并且请求响应返回的 cookie 包含 token
请求订单服务的下单接口(http://localhost:9600/extlight/order/place),但不携带 token,请求需要执行 zuul 过滤方法,请求响应 401 权限不足
请求订单服务的下单接口(http://localhost:9600/extlight/order/place),携带之前登录接口返回的 token,请求需要执行 zuul 过滤方法,校验通过后路由到订单服务执行之后的操作
测试效果图如下:

五、案例源码
六、参考资料
Announcing Zuul: Edge Service in the Cloud
Spring Cloud 入门 之 Zuul 篇(五)的更多相关文章
- Spring Cloud 入门 之 Config 篇(六)
原文地址:Spring Cloud 入门 之 Config 篇(六) 博客地址:http://www.extlight.com 一.前言 随着业务的扩展,为了方便开发和维护项目,我们通常会将大项目拆分 ...
- Spring Cloud 入门 之 Hystrix 篇(四)
原文地址:Spring Cloud 入门 之 Hystrix 篇(四) 博客地址:http://www.extlight.com 一.前言 在微服务应用中,服务存在一定的依赖关系,如果某个目标服务调用 ...
- Spring Cloud 入门 之 Ribbon 篇(二)
原文地址:Spring Cloud 入门 之 Ribbon 篇(二) 博客地址:http://www.extlight.com 一.前言 上一篇<Spring Cloud 入门 之 Eureka ...
- Spring Cloud 入门 之 Eureka 篇(一)
原文地址:Spring Cloud 入门 之 Eureka 篇(一) 博客地址:http://www.extlight.com 一.前言 Spring Cloud 是一系列框架的有序集合.它利用 Sp ...
- Spring Cloud 入门 之 Feign 篇(三)
原文地址:Spring Cloud 入门 之 Feign 篇(三) 博客地址:http://www.extlight.com 一.前言 在上一篇文章<Spring Cloud 入门 之 Ribb ...
- Spring Cloud入门教程 - Zuul实现API网关和请求过滤
简介 Zuul是Spring Cloud提供的api网关和过滤组件,它提供如下功能: 认证 过滤 压力测试 Canary测试 动态路由 服务迁移 负载均衡 安全 静态请求处理 动态流量管理 在本教程中 ...
- <Spring Cloud>入门六 Zuul
1.Zuul 2.操作 2.1 pom <?xml version="1.0" encoding="UTF-8"?> <project xml ...
- Spring Cloud 入门教程(九): 路由网关zuul
在微服务架构中,需要几个关键的组件,服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个组件可以组建一个简单的微服务架构.客户端的请求首先经过负载均衡(zuul.Ngnix),再 ...
- Spring Cloud第十四篇 | Api网关Zuul
本文是Spring Cloud专栏的第十四篇文章,了解前十三篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring C ...
随机推荐
- 51. N-Queens 52. N-Queens II *HARD*
1. 求所有解 The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two ...
- SSH 反向代理
SSH反向代理 被控制端没有NAT或者没有静态公网IP,把本端一台服务器映射到外网给远端SSH进来,建立SSH反向隧道. 先映射本端机器到外网 nat server 2222to22 protoco ...
- 信号处理函数的返回setjmp/longjmp
信号处理函数可以正常返回,也可以调用其他函数返回到程序的主函数中,而不是从该处理程序返回. 正如ANSI C标准所说明的,一个信号处理程序可以返回或者调用abort.exit或longjmp(goto ...
- 模拟QQ分组(具有伸缩功能) (添加开源框架的光闪烁效果)SimpleExpandableListAdapter 适配器的用法,并且可添加组及其组内数据。
package com.lixu.qqfenzu; import java.util.ArrayList; import java.util.HashMap; import java.util.Lis ...
- L1-030 一帮一
“一帮一学习小组”是中小学中常见的学习组织方式,老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组.本题就请你编写程序帮助老师自动完成这个分配工作,即在得到全班学生的排名后,在当前尚未分组的学生中, ...
- windows 开发者神器 tc – total command和替代品
作为开发者,windows上开发时,会运用一些神器,比如:total commander,搜索目录.查看文件.批量重命名等非常方便. tc是收费版的,有个免费的替代版本Just manager:htt ...
- 【笔记】《深入浅出MFC》第5章 总观Application Framework
凝聚性强.组织化强的类库就是Application Framework.一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework ...
- bga
本文记录在bga布线的难题. 1一开始就要预留好布线局域. 最近出现布线太密,修改时就麻烦了. http://bbs.elecfans.com/jishu_521995_1_1.html
- 设置MaskedTextBox控件的格式,掩码方式检验输入方式
#region 设置MaskedTextBox控件的格式,掩码方式检验输入方式 /// <summary> /// 将MaskedTextBox控件的格式设为yyyy-mm-dd格式. / ...
- np.stack() 与 tf.stack() 的简单理解
说明:np ----> numpy tf ----> tensorflownp.stack(arrays, axis=0) np.stack(arrays, axis=0) - ...