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 上实现限流是个不错的选 ...
随机推荐
- 2.使用Lucene开发自己的搜索引擎–indexer索引程序中基本类介绍
(1)Directory:Directory类描述了Lucene索引的存放位置,它是一个抽象,其子类负责具体制定索引的存储路径.FSDirectory.open方法来获取真实文件在文件系统中的存储路径 ...
- tableau绘制热力地图
一.右键国家地区和城市字段分别设置为地理角色-国家地区和城市 二.双击国家地区和城市添加到工作表 三.把订单id拖拽至标记卡的详细信息,标记改为密度显示,颜色设置为温度发散 四.最终整理结果如下图所示
- Mybatis环境搭建及测试
1.新建java project,导入相应jar包 本次使用到的mybatis-3.2.7版本 mybatis需要jar包:mybatis-3.2.7.jar.lib文件下的依赖jar mysql驱动 ...
- [BUUCTF]REVERSE——[MRCTF2020]hello_world_go
[MRCTF2020]hello_world_go 附件 步骤: 例行检查,64位程序,无壳 64位ida载入,检索程序里的字符串,有很多,直接检索flag 一个一个点过去,找到了flag 按a,提取 ...
- CF134A Average Numbers 题解
Content 有 \(n\) 个数 \(a_1,a_2,a_3,...,a_n\).试求出使得 \(a_i\) 与其他所有整数的算术平均值相等的所有 \(i\). 数据范围:\(2\leqslant ...
- CF742B Arpa's obvious problem and Mehrdad's terrible solution 题解
Content 有一个长度为 \(n\) 的数组,请求出使得 \(a_i \oplus a_j=x\) 且 \(i\neq j\) 的数对 \((i,j)\) 的个数.其中 \(\oplus\) 表示 ...
- django - Templates模板嵌套语法
模板继承 1.继承母板:{% extends '母板html文件名称' %} 2.包含子模板:{% include '子母板html 文件名' %} 模板内容分块 {% block <分块名& ...
- Linux(centos) 设置MySQL数据库不区分大小写
1.修改配置文件 vim /etc/my.cnf 在[mysqld]节点下,加入一行: lower_case_table_names=1 2.重启数据库服务 service mysqld restar ...
- 安装MingW64_配置C/C++开发环境_Windows10
下载安装 mingw-w64托管在sourceforge,下载地址: https://sourceforge.net/projects/mingw-w64/ 安装过程中... 除了下图的界面,其他选择 ...
- 【LeetCode】702. Search in a Sorted Array of Unknown Size 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历 二分查找 日期 题目地址:https://lee ...