本篇文章为系列文章,未读第一集的同学请猛戳这里:

哈喽沃德先生:Spring Cloud 系列之 Netflix Zuul 服务网关(一)​zhuanlan.zhihu.com

本篇文章讲解 Zuul 网关过滤器实现统一鉴权以及网关过滤器异常统一处理。

网关过滤器

https://www.zhihu.com/video/1234207041360777216

Zuul 包含了对请求的路由和过滤两个核心功能,其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础;而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。然而实际上,路由功能在真正运行时,它的路由映射和请求转发都是由几个不同的过滤器完成的。

路由映射主要通过 pre 类型的过滤器完成,它将请求路径与配置的路由规则进行匹配,以找到需要转发的目标地址;而请求转发的部分则是由 routing 类型的过滤器来完成,对 pre 类型过滤器获得的路由地址进行转发。所以说,过滤器可以说是 Zuul 实现 API 网关功能最核心的部件,每一个进入 Zuul 的 http 请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。

关键名词

  • 类型:定义路由流程中应用过滤器的阶段。共 pre、routing、post、error 4 个类型。
  • 执行顺序:在同类型中,定义过滤器执行的顺序。比如多个 pre 类型的执行顺序。
  • 条件:执行过滤器所需的条件。true 开启,false 关闭。
  • 动作:如果符合条件,将执行的动作。具体操作。

过滤器类型

  • pre:请求被路由到源服务器之前执行的过滤器

    • 身份认证
    • 选路由
    • 请求日志
  • routing:处理将请求发送到源服务器的过滤器
  • post:响应从源服务器返回时执行的过滤器
    • 对响应增加 HTTP 头
    • 收集统计和度量指标
    • 将响应以流的方式发送回客户端
  • error:上述阶段中出现错误时执行的过滤器

入门案例

创建过滤器

Spring Cloud Netflix Zuul 中实现过滤器必须包含 4 个基本特征:过滤器类型,执行顺序,执行条件,动作(具体操作)。这些步骤都是 ZuulFilter 接口中定义的 4 个抽象方法:

package com.example.filter;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;/*** 网关过滤器*/
@Component
public class CustomFilter extends ZuulFilter {private static final Logger logger = LoggerFactory.getLogger(CustomFilter.class);/*** 过滤器类型*      pre*      routing*      post*      error** @return*/@Overridepublic String filterType() {return "pre";}/*** 执行顺序*      数值越小,优先级越高** @return*/@Overridepublic int filterOrder() {return 0;}/*** 执行条件*      true 开启*      false 关闭** @return*/@Overridepublic boolean shouldFilter() {return true;}/*** 动作(具体操作)*      具体逻辑** @return* @throws ZuulException*/@Overridepublic Object run() throws ZuulException {// 获取请求上下文RequestContext rc = RequestContext.getCurrentContext();HttpServletRequest request = rc.getRequest();logger.info("CustomFilter...method={}, url={}",request.getMethod(),request.getRequestURL().toString());return null;}}

  • filterType:该函数需要返回一个字符串代表过滤器的类型,而这个类型就是在 http 请求过程中定义的各个阶段。在 Zuul 中默认定义了 4 个不同的生命周期过程类型,具体如下:

    • pre:请求被路由之前调用
    • routing: 路由请求时被调用
    • post:routing 和 error 过滤器之后被调用
    • error:处理请求时发生错误时被调用
  • filterOrder:通过 int 值来定义过滤器的执行顺序,数值越小优先级越高。
  • shouldFilter:返回一个 boolean 值来判断该过滤器是否要执行。
  • run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续路由,或是在请求路由返回结果之后,对处理结果做一些加工等。

访问

访问:http://localhost:9000/product-service/product/1 控制台输出如下:

CustomFilter...method=GET, url=http://localhost:9000/product-service/product/1

统一鉴权

接下来我们在网关过滤器中通过 token 判断用户是否登录,完成一个统一鉴权案例。

创建过滤器

package com.example.filter;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.http.HttpStatus;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;/*** 权限验证过滤器*/
@Component
public class AccessFilter extends ZuulFilter {private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);@Overridepublic String filterType() {return "pre";}@Overridepublic int filterOrder() {return 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {// 获取请求上下文RequestContext rc = RequestContext.getCurrentContext();HttpServletRequest request = rc.getRequest();// 获取表单中的 tokenString token = request.getParameter("token");// 业务逻辑处理if (null == token) {logger.warn("token is null...");// 请求结束,不在继续向下请求。rc.setSendZuulResponse(false);// 响应状态码,HTTP 401 错误代表用户没有访问权限rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());// 响应类型rc.getResponse().setContentType("application/json; charset=utf-8");PrintWriter writer = null;try {writer = rc.getResponse().getWriter();// 响应内容writer.print("{"message":"" + HttpStatus.UNAUTHORIZED.getReasonPhrase() + ""}");} catch (IOException e) {e.printStackTrace();} finally {if (null != writer)writer.close();}} else {// 使用 token 进行身份验证logger.info("token is OK!");}return null;}}

访问

访问:http://localhost:9000/product-service/product/1 结果如下:

访问:http://localhost:9000/product-service/product/1?token=abc123 结果如下:

Zuul 请求的生命周期

  1. HTTP 发送请求到 Zuul 网关
  2. Zuul 网关首先经过 pre filter
  3. 验证通过后进入 routing filter,接着将请求转发给远程服务,远程服务执行完返回结果,如果出错,则执行 error filter
  4. 继续往下执行 post filter
  5. 最后返回响应给 HTTP 客户端

网关过滤器异常统一处理

https://www.zhihu.com/video/1234207208662945792

创建过滤器

package com.example.filter;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.http.HttpStatus;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.io.PrintWriter;/*** 异常过滤器*/
@Component
public class ErrorFilter extends ZuulFilter {private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);@Overridepublic String filterType() {return "error";}@Overridepublic int filterOrder() {return 0;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {RequestContext rc = RequestContext.getCurrentContext();Throwable throwable = rc.getThrowable();logger.error("ErrorFilter..." + throwable.getCause().getMessage(), throwable);// 响应状态码,HTTP 500 服务器错误rc.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());// 响应类型rc.getResponse().setContentType("application/json; charset=utf-8");PrintWriter writer = null;try {writer = rc.getResponse().getWriter();// 响应内容writer.print("{"message":"" + HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase() + ""}");} catch (IOException e) {e.printStackTrace();} finally {if (null != writer)writer.close();}return null;}}

模拟异常

在 pre 过滤器中添加模拟异常代码。

// 模拟异常
Integer.parseInt("zuul");

配置文件

禁用 Zuul 默认的异常处理 filter:SendErrorFilter

zuul:# 禁用 Zuul 默认的异常处理 filterSendErrorFilter:error:disable: true

访问

访问:http://localhost:9000/product-service/product/1 结果如下:

下一篇我们讲解 Zuul 和 Hystrix 的无缝结合,实现网关监控、网关熔断、网关限流、网关调优,记得关注噢~

大家可以通过 分类 查看更多关于 Spring Cloud 的文章。

本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议

您的点赞转发是对我最大的支持。

扫码关注 哈喽沃德先生「文档 + 视频」每篇文章都配有专门视频讲解,学习更轻松噢 ~

springcloud 网关_Spring Cloud 系列之 Netflix Zuul 服务网关(二)相关推荐

  1. Spring Cloud 系列之 Netflix Zuul 服务网关(三)

    本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Netflix Zuul 服务网关(一) Spring Cloud 系列之 Netflix Zuul 服务网关(二) ...

  2. Spring Cloud 系列之 Netflix Ribbon 负载均衡

    什么是 Ribbon Ribbon 是一个基于 HTTP 和 TCP 的 客服端负载均衡工具,它是基于 Netflix Ribbon 实现的. 它不像 Spring Cloud 服务注册中心.配置中心 ...

  3. Spring Cloud浅谈个人尝鲜------Zuul 服务网关(五)

    Spring Cloud浅谈个人尝鲜------Zuul 服务网关(五) 前面几篇文章我们学习了Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服务的熔断防止 ...

  4. apollo 配置中心_Spring Cloud 系列之 Apollo 配置中心(三)

    本篇文章为系列文章,未读前几集的同学请猛戳这里: 哈喽沃德先生:Spring Cloud 系列之 Apollo 配置中心(一)​zhuanlan.zhihu.com 哈喽沃德先生:Spring Clo ...

  5. Zuul服务网关二个功能请求的路由和过滤器使用

    Zuul服务网关 1.理解Zuul ​ Zuul 是从设备和网站到应用程序后端的所有请求的前门.作为边缘服务应用程序,Zuul 旨在实现动 态路由,监视,弹性和安全性.Zuul 包含了对请求的路由和过 ...

  6. Spring Cloud(八)Zuul路由网关

    文章目录 1 概述 1.1 什么是Zuul 1.2 为什么要建造Zuul 1.3 Zuul有哪些功能 1.4 理解 2 Zuul路由功能 2.1 创建zuul服务 2.2 测试 2.3 路由访问映射规 ...

  7. Spring Cloud第五章:服务网关Zuul

    在微服务架构中,需要几个关键的组件,服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个组件可以组建一个简单的微服务架构,如下图: 客户端的请求首先经过负载均衡(zuul.Ngn ...

  8. SpringCloud Zuul服务网关实操

    鉴权 接上篇来,写一个简单的鉴权 请求必须携带token参数,若无token,则拒绝请求 其中 filterType--过滤器类型,这里使用PRE_TYPE前置 filterOrder--过滤器顺序, ...

  9. eureka集群只注册一个_Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇

    Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇 本文主要内容: 1:spring cloud整合Eureka总结 本文是由凯哥(凯哥Java:kagejava ...

最新文章

  1. Hibernate的openSession和getCurrentSession区别
  2. 方法:查询MongoDB数据库中最新一条数据(JAVA)
  3. 硬件基础 —— 电容
  4. 【转载】Windows自带.NET Framework版本大全
  5. 中年发福谁之“过”?Science论文采用“双标水”法首次揭示全生命周期代谢规律...
  6. 【Python】解析Python中的条件语句和循环语句
  7. 串口和TCP测试工具
  8. 开始学习爬虫:爬虫之爬取电影天堂网站资源到本地mysql数据库
  9. layui表格中显示内容换行
  10. 【中英】【吴恩达课后编程作业】Course 4 -卷积神经网络 - 第四周作业
  11. Windows 缓冲区溢出与数据执行保护DEP
  12. Point Attention Network for Semantic Segmentation of 3D Point Clouds 论文解析
  13. Incorrect string value: ‘\xF0\x9F\x91\x82‘ for column ‘address‘ at row 1
  14. 应用程序无法正常启动(0x000007b)的不常见的解决过程
  15. OSChina 周四乱弹 ——老司机的幼年日常
  16. Arduino Infrared controller
  17. swiper 上滑触发_最火英雄小书包:用最矮的身高,打出最高的输出,死上最多的次数...
  18. 遗忘爱GhostXP SP2个人收藏版2007
  19. IBM WebSphere Application Server与IBM Java V8官方帮助文档资源汇总
  20. emmc和ssd的区别【转】

热门文章

  1. java--自动装箱,拆箱
  2. linux连接外部库时候编译,交叉编译时如何使用外部库?
  3. 6种java垃圾回收算法_被说烂了的Java垃圾回收算法,我带来了最“清新脱俗”的详细图解...
  4. plt.errorbar画误差曲线
  5. python的print函数输出带颜色字体
  6. matlab的傅里叶变换
  7. postman测试 上传下载文件
  8. 优先队列priority_queue的使用方式
  9. 设计模式--观察者模式
  10. 免otp动态密码登录堡垒机