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 多层拦截 --- 心得的更多相关文章

  1. Spring Cloud Zuul网关 Filter、熔断、重试、高可用的使用方式。

    时间过的很快,写springcloud(十):服务网关zuul初级篇还在半年前,现在已经是2018年了,我们继续探讨Zuul更高级的使用方式. 上篇文章主要介绍了Zuul网关使用模式,以及自动转发机制 ...

  2. 笔记:Spring Cloud Zuul 快速入门

    Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...

  3. Spring Cloud Zuul 限流详解(附源码)(转)

    在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. ...

  4. Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务

    API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...

  5. Spring Cloud Zuul 快速入门

    Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...

  6. 第七章 API网关服务:Spring Cloud Zuul

    API网关是一个更为智能的应用服务器, 它的定义类似于面向对象设计模式中的Facade模式, 它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来进行调度和过滤.它除了要实现 ...

  7. SpringCloud---API网关服务---Spring Cloud Zuul

    1.概述 1.1 微服务架构出现的问题   及  解决: 1.1.1 前言 每个微服务应用都提供对外的Restful API服务,它通过F5.Nginx等网络设备或工具软件实现对各个微服务的路由与负载 ...

  8. Spring Cloud Zuul API服务网关之请求路由

    目录 一.Zuul 介绍 二.构建Spring Cloud Zuul网关 构建网关 请求路由 请求过滤 三.路由详解 一.Zuul 介绍 ​ 通过前几篇文章的介绍,我们了解了Spring Cloud ...

  9. Spring Cloud(十二):Spring Cloud Zuul 限流详解(附源码)(转)

    前面已经介绍了很多zuul的功能,本篇继续介绍它的另一大功能.在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Cloud中如何实现限流. 在 Zuul 上实现限流是个不错的选 ...

随机推荐

  1. angular关于select的留白问题

    Angular select留白的问题 小白的总结,大神勿喷:需要转载请说明出处,如果有什么问题,欢迎留言 总结:出现留白说明你的ng-model的值在option的value中没有对应的值: 一.直 ...

  2. 『学了就忘』Linux服务管理 — 75、Linux系统中的服务

    目录 1.服务的介绍 2.Windows系统中的服务 3.Linux系统中服务的分类 4.独立的服务和基于xinetd服务的区别 5.如何查看一个服务是独立的服务还是基于xinetd的服务 (1)查看 ...

  3. Redis5.0.8 Cluster集群部署

    目录 一.Redis Cluster简介 二.部署 三.创建主库 一.Redis Cluster简介 Redis Cluster集群是一种去中心化的高可用服务,其内置的sentinel功能可以提供高可 ...

  4. cron 获取下次运行时间(基于 C# + Quartz.NET)

    代码 Quartz 的 cron 支持秒,导致一些 cron 库无法准确的获得下次执行时间,这里使用 Quartz.Net 自带的方法来获取下次执行时间. //引用 Quartz CronExpres ...

  5. k8s-statefulset

    1. 简介 StatefulSet 是用来管理有状态应用的工作负载Api对象. StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符. 和 Dep ...

  6. ASP.NET MVC 导入Excel文件(完整版)

    View视图部分: <form method="post" enctype="multipart/form-data" action="/Pos ...

  7. 【LeetCode】345. Reverse Vowels of a String 解题报告(Java & Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 使用栈 双指针 日期 [LeetCode] 题目地址 ...

  8. 【LeetCode】Largest Number 解题报告

    [LeetCode]Largest Number 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/largest-number/# ...

  9. 写在LeetCode刷题600题

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 从2015年9月刷题至今,我终于在LeetCode刷够600道题了.从刚开始的Java语 ...

  10. 【LeetCode】822. Card Flipping Game 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址:https://leetcode.com/problems/card-flip ...