spring cloud Zuul 多层拦截 --- 心得
1.前言
根据教材、博客文章的实例实操,基本都是单层拦截,没有找到多层拦截的具体写法 ,让我走了很多弯路,我将其写在这里,以待以后参考。
2.环境
spring boot : 2.1.6.RELEASE
spring cloud : Greenwich.SR2
3.准备一个端口为5001 的 Zuul网关
目录结构
导入依赖
<!--zuul 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cen.cloud</groupId>
<artifactId>cen-mycloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>zuul-server-5001</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul-server-5001</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--==========================================================================-->
<!--eureka 注册中心依赖包 -->
<!-- 这是服务中心端的依赖包-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>-->
<!-- </dependency>-->
<!-- 可是服务客户端的依赖包,两个包都有一样的功能-发现服务,但是下面这个包无 服务端的注解-->
<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> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
application.properties 文件 ,设置自定义映射,路径含有/bd/则路由到 百度首页 ,用于测试
spring.application.name=zuul-server-5001
server.port=5001
#
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/
#全局添加前缀,如 localhost:114/myzuul/test/bb ,用于识别是否需要转发路由操作
#不可使用 /zuul ,猜测这是保留字
zuul.prefix=/mzuul
#//默认是false,这里是全局配置
#zuul.strip-prefix: //是否将这个代理前缀去掉
#
#忽略所有的,表示禁用默认路由,只认我们自己配置的路由.
#zuul.ignored-services="*"
#
#自定义路由设置
#拦截路径
zuul.routes.bd.path=/bd/**
#拦截后访问的指定地址
zuul.routes.bd.url=https://www.baidu.com/
#
##拦截路径
#zuul.routes.CONSUMER-9001.path=/CONSUMER-9001/**
##拦截后访问的指定地址
#zuul.routes.CONSUMER-9001.service-id=CONSUMER-9001
#
#拦截后访问的指定服务,使用服务名,根据注册中心获取的服务列表映射具体服务ip地址
#zuul.routes.api-b.service-id=520LOVE #http://localhost:5001/mzuul/CONSUMER-9001/gettname # 心得 :如果使用 服务列表默认映射的 拦截路径 ,则写在 httpurl 的服务名必须小写 ,即便 远程服务名 有大小写字符 ,
# 但在请求路径也必须全部改成小写 ,否则报错 404
第一层拦截 LoginFilter文件
package com.example.zuulserver5001.myFilter; import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException; //注册bean ,不使用@Component注解则需要去启动类创建一个方法new一个LoginFilter类后
// 使用 @bean注解注册bean,一样的作用
@Component
public class LoginFilter extends ZuulFilter { /**
* 选择过滤器类型
*/
@Override
public String filterType() {
//一共有下面4种过滤器
// public static final String ERROR_TYPE = "error";
// public static final String POST_TYPE = "post";
// public static final String PRE_TYPE = "pre";
// public static final String ROUTE_TYPE = "route";
return FilterConstants.PRE_TYPE;
} /**
* 通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
*/
@Override
public int filterOrder() {
return 0;
} /**
* 返回一个`Boolean`值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
*/
@Override
public boolean shouldFilter() {
return true;
} /**
* 过滤器的具体业务逻辑
*/
@Override
public Object run() throws ZuulException {
System.out.println("进入zuul拦截-login拦截");
//获取上下文
RequestContext ctx = RequestContext.getCurrentContext();
//获取Request
HttpServletRequest request = ctx.getRequest();
//获取请求参数
String token = request.getParameter("token");
System.out.println("参数token=" + token);
//
//
if (StringUtils.isBlank(token)) {
//参数内容为空
//拦截,拒绝路由
ctx.setSendZuulResponse(false);
//返回状态码
ctx.setResponseStatusCode(401);
//返回的响应体信息
try {
//不可以直接写中文,前端会显示中文乱码,加上这就解决中文乱码问题
//以文本格式显示,字体比较大
ctx.getResponse().setContentType("text/html;charset=UTF-8");
//以json格式显示,字体比较小
// ctx.getResponse().setContentType("application/json;charset=UTF-8");
// 上一句等同于 ctx.getResponse().setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
//
ctx.getResponse().getWriter().write("token is 空的-------401");
} catch (IOException e) {
e.printStackTrace();
}
} return null;
}
}
第二层拦截 LoginCheckFilter文件
package com.example.zuulserver5001.myFilter; import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.logging.Filter; @Component
public class LoginCheckFilter extends ZuulFilter {
//上下文,不可以设为 private
RequestContext ctx = null;
//Request
private HttpServletRequest request = null; @Override
public String filterType() {
return FilterConstants.PRE_TYPE;
} @Override
public int filterOrder() {
return 1;
} @Override
public boolean shouldFilter() {
System.out.println("进入zuul拦截-loginCheck拦截,判断是否开启该拦截");
//获取上下文
ctx = RequestContext.getCurrentContext();
// 判断上一层拦截是否通过
if(!ctx.sendZuulResponse()){
//上一层拦截不通过
System.out.println(" 上一层拦截不通过,不开启loginCheck拦截");
//该拦截不需要开启
return false;
}
//上层拦截通过
//获取Request
request = ctx.getRequest();
//获取请求路径
String urlStr = request.getRequestURI().toString();
//当访问路径含有/mzuul/bd/则开启该拦截
return urlStr.contains("/mzuul/bd");
} @Override
public Object run() throws ZuulException {
System.out.println("运行loginCheck拦截逻辑");
//获取请求参数
String token = request.getParameter("token");
System.out.println("---参数token=" + token);
if (StringUtils.isBlank(token) | (token != null && !token.equals("kk"))) {
// token 是空的 或者 不是 kk
//拦截
System.out.println("拦截,拒绝路由请求, token 是空的 或者 不是 kk");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(7781);
try {
ctx.getResponse().setContentType("text/html;charset=UTF-8");
ctx.getResponse().getWriter().write("请求参数="+token+",当参数是kk才可以通过");
} catch (IOException e) {
e.printStackTrace();
}
} return null;
}
}
启动类
package com.example.zuulserver5001; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.EnableZuulServer; @SpringBootApplication
//开启发现服务
@EnableEurekaClient
//开启zuul网关代理
@EnableZuulProxy
public class ZuulServer5001Application { public static void main(String[] args) {
SpringApplication.run(ZuulServer5001Application.class, args);
} }
图中指示的文件是熔断回路操作 ,在另一篇随笔详细讲解,这里不解释,因为用不上
4.测试
浏览器 访问 端口5001 ,http://localhost:5001/mzuul/bd
可见被第一层拦截了并判定不通过 ,进入了第二次拦截时被判断不开启第二次过滤
再次访问 http://localhost:5001/mzuul/bd?token=ghj
可见第一层拦截通过了 ,进入第二层拦截 被判定了开启第二次过滤 ,在第二次过滤 操作判定为不通过
再次访问 http://localhost:5001/mzuul/bd?token=kk
可见成功将请求路由到了 百度首页 ,通过了第一、二层过滤 ,参数符合要求 ,举一反三 ,可以在拦截逻辑加入身份认证等操作 ,如加入shiro 、 security等安全框架配合使用
5.其他心得
(1)如果配合eureka ,可使用远程服务名的全小写为路由关键字来映射到指定的远程服务去,
如果远程服务名 为 conSUmer-9001
不可使用
#http://localhost:5001/mzuul/CONSUMER-9001/gettname
或
#http://localhost:5001/mzuul/conSUmer-9001/gettname
必须写成全小写
#http://localhost:5001/mzuul/consumer-9001/gettname
但是必须开启默认路由 ,不写这个配置即可 ,默认使用默认路由
#忽略所有的,表示禁用默认路由,只认我们自己配置的路由.
#zuul.ignored-services="*"
(2) 前缀不可以使用zuul
#不可使用 /zuul ,猜测这是保留字
zuul.prefix=/mzuul
(3)不论是什么请求,只有经过zuul都会执行一篇所有的过滤拦截,顺序是根据filterOrder()方法的返回值来判定的 ,通过返回的正整数值来定义过滤器的执行顺序,数字越小优先级越高
/**
* 通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
*/
@Override
public int filterOrder() {
return 0;
}
因此 ,在每层过滤文件需要做判断这个请求是否需要开启这个过滤的操作逻辑 ,
只要上一层有一个过滤不通过,下面的过滤都没必要在执行,
spring cloud Zuul 多层拦截 --- 心得的更多相关文章
- Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式。
时间过的很快,写springcloud(十):服务网关zuul初级篇还在半年前,现在已经是2018年了,我们继续探讨Zuul更高级的使用方式. 上篇文章主要介绍了Zuul网关使用模式,以及自动转发机制 ...
- 笔记:Spring Cloud Zuul 快速入门
Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...
- Spring Cloud Zuul 限流详解(附源码)(转)
在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. ...
- Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务
API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...
- Spring Cloud Zuul 快速入门
Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...
- 第七章 API网关服务:Spring Cloud Zuul
API网关是一个更为智能的应用服务器, 它的定义类似于面向对象设计模式中的Facade模式, 它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来进行调度和过滤.它除了要实现 ...
- SpringCloud---API网关服务---Spring Cloud Zuul
1.概述 1.1 微服务架构出现的问题 及 解决: 1.1.1 前言 每个微服务应用都提供对外的Restful API服务,它通过F5.Nginx等网络设备或工具软件实现对各个微服务的路由与负载 ...
- Spring Cloud Zuul API服务网关之请求路由
目录 一.Zuul 介绍 二.构建Spring Cloud Zuul网关 构建网关 请求路由 请求过滤 三.路由详解 一.Zuul 介绍 通过前几篇文章的介绍,我们了解了Spring Cloud ...
- Spring Cloud(十二):Spring Cloud Zuul 限流详解(附源码)(转)
前面已经介绍了很多zuul的功能,本篇继续介绍它的另一大功能.在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选 ...
随机推荐
- Windows下搭建FFmpeg开发调试环境
背景 如果你是一个FFmpeg的使用者,那么绝大部分情况下只需要在你的程序中引用FFmpeg的libav*相关的头文件,然后在编译阶段链接相关的库即可. 但是如果你想调试FFmpeg内部相关的逻辑,或 ...
- RabbitMQ,RocketMQ,Kafka 几种消息队列的对比
常用的几款消息队列的对比 前言 RabbitMQ 优点 缺点 RocketMQ 优点 缺点 Kafka 优点 缺点 如何选择合适的消息队列 参考 常用的几款消息队列的对比 前言 消息队列的作用: 1. ...
- 【代码优化】List.remove() 剖析
一.犯错经历 1.1 故事背景 最近有个需求大致的背景类似: 我已经通过一系列的操作拿到一批学生的考试成绩数据,现在需要筛选成绩大于 95 分的学生名单. 善于写 bug 的我,三下五除二完成了代码的 ...
- [BUUCTF]REVERSE——rsa
rsa 附件 题目是rsa,首先了解一下什么是rsa加密,具体的看这个文章 首先大概介绍下RSA加密解密 RSA加密是对明文的E次方后除以N后求余数的过程 公钥n = p * q,其中p和q是两个大素 ...
- Windows通过计划任务定时执行bat文件
第一步 第二步 第三步 第四步 第五步 第六步
- 使用 juqery.media.js 实现 pdf 预览
作用:可以实现在指定的位置预览PDF 缺点: (1)在iPad上只能预览一页PDF.(问题是iPad会将PDF转为img呈现,试了将img宽度设置为100%方法但并不好使) (2)在安卓上不能预览,依 ...
- WPF DataGrid OxyPlot 卡顿优化
不是优化,我是想用这个标题吸引遇到相同问题的同学过来看看. UI如下,左边DataGrid有7列,右边OxyPlot显示折线图 列表4000+数据,折线图4000+个点,页面卡的用不了. 体现就是列表 ...
- SpringBoot项目使用Caffeine本地缓存
环境配置:(或以上版本,必须) JDK 版本:1.8 Caffeine 版本:2.8.0SpringBoot 版本:2.2.2.RELEASE 也可以不与SpringBoot结合 1.添加maven ...
- git修改账号密码
查看当前用户名和邮箱 git config user.name git config user.email 修改 git config --global user.name "新用户名&qu ...
- c++之Linux获取可用串口
1.关于 这份代码来自: stackoverflow 2. 测试 2.1 测试环境: vmware + ubuntu, vmware添加串口(虚拟机关机后再添加) 2.2 测试输出 3. 源码 #in ...