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

287888448c3cb2c192f7dff0fa6af34a.png

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

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

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

网关过滤器

20aebf9e6dae249c03924d46591a03cb.png
https://www.zhihu.com/video/1234207041360777216

76d986b2d361d2d138c8c03d20d6734c.png

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 结果如下:

84298af2f6d012494d033c99e9f412fc.png

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

cce2698a8de7763246ec2a2a1904bd7f.png

Zuul 请求的生命周期

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

网关过滤器异常统一处理

470ee5ca2e8d64bcbd979e1aaf392bbc.png
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 结果如下:

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

66e3392d9d987ff0da6553eb478489b6.gif

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

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

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

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

595b6a3d92da93afb4ae2c00236d26f4.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/504256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode笔记】207. 课程表(Java、图、BFS、队列)

文章目录题目描述思路 && 代码二刷题目描述 刷的第一道图相关的题,简直考古要复习一下拓扑、邻接矩阵之类的知识啦 思路 && 代码 前置课程看成入度,后置课程看成出度对于入度,只需要记录有多少即可。对于出度&#xff0c…

【LeetCode笔记】399. 除法求值(Java、图)

文章目录题目描述思路 && 代码题目描述 第二道图题,大概是hot100里唯二的图题了。。 思路 && 代码 邻接矩阵存储,g[i][j] 代表 i / j 的值通过已知的表达式,对矩阵进行维护(包括间接得到的值,见注…

【LeetCode笔记】406. 根据身高重建队列(Java、偏数学)

文章目录题目描述思路 && 代码二刷题目描述 老阅读题了 ,第一遍看题的时候一脸懵逼但其实代码就6行(嘿嘿) 思路 && 代码 先按照身高降序排,再按照人数升序排(套路题) class Solution…

ssd内部是多个flash一起操作_一键自毁军工级SSD固态硬盘的技术亮点

通过短路方式实现,烧毁时可见明火及冒烟,5秒(时间可调整)防误触发功能,每2秒烧毁一片闪存芯片,独特的反馈电路实时反馈烧毁状态,确保所有闪存全部被烧毁。烧毁后电子盘彻底报废,无法通过任何手段恢复数据。…

【LeetCode笔记】309. 最佳买卖股票时机含冷冻期(Java、动态规划)

文章目录题目描述思路 && 代码二刷题目描述 股票系列!这次加入了冷冻期要素,需要考虑更多的状态 思路 && 代码 每天,都有三个状态:开一个 dp int[n][3] 二维数组主要思路…就是理解几种状态,以及…

sun 些命令可以将服务器设置至ok模式_Python 高手之路:从零开始打造一个Web服务器...

文 | Ruslan Spivak 译 | EarlGrey 推荐 | 编程派公众号(ID:codingpy)有一天,一位女士散步时经过一个工地,看见有三个工人在干活。她问第一个人,“你在做什么?”第一个人有点不高兴,吼道“难道你看不出来我…

css 查看更多_在Scrapy中如何利用CSS选择器从网页中采集目标数据——详细教程(上篇)...

/前言/今天小编给大家介绍Scrapy中另外一种选择器,即大家经常听说的CSS选择器。/CSS基础/CSS选择器和Xpath选择器的功能是一致的,都是帮助我们去定位网页结构中的某一个具体的元素,但是在语法表达上有区别。Xpath选择器明明已经可以帮助我们提…

【LeetCode笔记】85. 最大矩形(Java、单调栈)

文章目录题目描述思路 && 代码二刷题目描述 其实是84. 柱状图中最大的矩形的兄弟题目,理解成多个84题,对结果取max即可。 思路 && 代码 一行抽象出一个【柱状图】,分别套到84题的函数里即可时空复杂度:O(n2n…

c4d启动无反应_浙江无填料喷雾式冷却塔

浙江无填料喷雾式冷却塔大容量静压储能设备广泛运用在厂区全热力、城市交通和道路通行中,全循环泵吸式:由高效的系统循环和分区启动两个关键部件组成。其进、出口均采用橡胶隔墙为隔离设施;提供一个保证阀体抗剪力的安全及密封的良好环境&…

【LeetCode笔记】312. 戳气球(Java、动态规划)

文章目录题目描述思路 && 代码二刷题目描述 一眼动态规划,但思路确实不好想面试被问过,直接人没了 思路 && 代码 核心思路:关心【最后一个被爆的气球】,自底向上进行动态规划 class Solution {// 思路&…

selinux= 为 disabled_安德里茨为巴西KLabin Puma II 项目提供气化炉和生物质处理线

ANDRITZ to supply gasification plant and biomass handling line to Klabin’s Puma II project in Brazil.国际技术集团公司安德里茨收到KLabin的订单,为其位于巴西的Ortigueira浆厂提供一台完整的生物质气化炉和一条新的生物质处理线。International technology…

【LeetCode笔记】301. 删除无效的括号(Java、DFS、字符串)

文章目录题目描述思路 && 代码二刷题目描述 【所有可能结果】-> 【暴力DFS】 思路 && 代码 代码比较长,但是总体思路很清晰。剪枝:舍弃左括号、舍弃右括号两种情况(见注释)分情况:当前字符有【左…

css3宽度变大动画_动画演示流量计的工作原理

​流量计(Flowmeter)是工业生产的眼睛,与国民经济、国防建设、科学研究有着密切的关系,在国民经济中占据重要地位与作用,可用于气体、液体、蒸汽等介质流量的测量。为了更好的展示流量计测量原理,小编采用动画演示的方法来给大家介…

cfiledialog 保存 扩展名_儿童美术:油画棒 插画一组超萌的大饼脸小孩 保存了跟小朋友一起画吧...

儿童美术:油画棒 插画一组超萌的大饼脸小孩 保存了跟小朋友一起画吧今天继续带来Hannah Sun的“大饼脸”系列。画者使用的作画工具为油画棒,因其效果厚重的特点,与人物的笨拙特征相得益彰,从而让人过目不忘。01020304050607这些作…

【LeetCode笔记】253. 会议室 II(Java、偏数学)

文章目录题目描述思路 && 代码计划里 hot 100 剑指Offer 的题目中唯一一道会员题,同时也是最后一道没写的题,刚好今天 leetcode 发了一天会员可以写上…简直命运石之门的选择,感动! 题目描述 转化成上下车问题&#xff…

【学习笔记】第二章——管程(解决生产者消费者问题、封装、Java 体现)

填坑系列!立个这几天补完的 Flag 因为这个视频的笔记,很多人都已经写得很好了,所以接下来的博客,只会记录一些 【常考】【和 Java 相关】【感觉很有必要记录】的内容 文章目录一. 概念二. 用于解决生产者、消费者问题Java 里的管程…

手机浏览器网址_打开URL(在其他应用中访问网址)app下载-打开URL(在其他应用中访问网址)v2.6安卓版下载...

打开URL让你能够在其它的软件当中打开你所需要的页面,下面就由微侠网小编给您介绍这款软件,相对来说就是在你手机当中的任何一个软件当中加入内置的浏览器,让你将各种网址在你所需要的地点当中打开,这对于用户能够能够起到一定的帮助的作用&a…

基于fpga的dds函数信号发生器的设计_超声信号功率放大器驱动压电陶瓷测试

压电陶瓷片是一种电子发音元件,以锆钛酸铅压电陶瓷材料制成。基于压电效应原理,当在两片电极上面接通交流音频信号时,压电片会根据信号的大小频率发生震动而产生相应的声音来。压电陶瓷驱动电源的性能直接关系着高精度微位移的实现&#xff0…

【学习笔记】第三章——内存 I(交换技术、进程七状态模型、动态分区分配、动态分区算法)

文章目录一. 交换状态、进程七状态模型二. 内存的分配方式三. 动态分配算法一. 交换状态、进程七状态模型 交换技术:内存空间紧张,把某些进程暂时换出外存。(进程在内存与磁盘间动态调度)进程七状态:相对于五状态&…

ktv管理系统_KTV经营管理的几个原则

KTV的竞争已经到了拼综合实力的阶段,向管理要效益、建立完善的KTV企业管理体系的重要性已经不言而喻了,建立全面的管理体系,可以促进KTV整体管理工作同步化、协调化,全面提升管理绩效,是KTV企业立足市场,基…