一、简介

Spring Cloud Zuul主要的功能是:路由跳转以及路由过滤,本文主要讲解了这两方面的内容。在实际项目中,zuul中可能也会有相对复杂的逻辑,通常在zuul前面还有一个nginx反向代理,前端直接访问nginx,让nginx给我们代理到网关服务,网关服务再路由到具体的服务提供者上。zuul默认集成了ribbon实现了负载均衡功能。

二、准备工程

a. zuul-eureka-server,端口1111

b.zuul-service:服务提供者,端口2222

c.zuul-api-gateway:网关服务,端口3333

本文不对eureka服务注册中心的搭建做过多讲解,主要讲解api-gateway网关服务的搭建过程。

三、新建zuul-service服务提供者工程

zuuk-service也只是一个比较简答的服务提供者,主要是要暴露一个接口给外部进行访问。主要代码如下:

pom.xml:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.springcloud.wsh</groupId><artifactId>springcloud_zuul_service</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>springcloud_zuul_service</name><description>服务提供者</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring-cloud.version>Camden.SR6</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class SpringcloudZuulServiceApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudZuulServiceApplication.class, args);}
}

ZuulServiceController:

/*** @Title: ZuulServiceController* @ProjectName springcloud_zuul_api_gateway* @Description: 对外提供接口服务* @Author WeiShiHuai* @Date 2018/9/14 14:16*/
@RestController
public class ZuulServiceController {private static Logger logger = LoggerFactory.getLogger(ZuulServiceController.class);@Value("${server.port}")private String port;@RequestMapping("/getInfo/{name}")public String getInfo(@PathVariable("name") String name) {String info = "hello " + name + " ,i am from zuul service,port = " + port;logger.info(info);return info;}}

四、新建zuul-api-gateway工程

首先引入zuul的依赖,具体pom.xml如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.springcloud.wsh</groupId><artifactId>springcloud_api_gateway</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>springcloud_api_gateway</name><description>Spring Cloud Zuul服务网关</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring-cloud.version>Camden.SR6</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zuul</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

五、启动类加上@EnableZuulProxy注解

@EnableZuulProxy注解主要是用于开启zuul路由转发以及路由过滤功能。


/*** @Description: api网关启动类* @Author: WeiShiHuai* @Date: 2018/9/14 14:22* Zuul的主要功能是路由转发和过滤器* 通常情况下,可以在网关服务进行权限控制等,将具体业务逻辑与权限控制分开,有利于解耦; Zuul也可以实现对服务的负载均衡* Zuul主要作用是请求转发,和过滤,请求转发是做了负载均衡。Zuul也需要做一次集群,因为 Zuul是网关,可能需要做很复杂的逻辑,比如查数据库,还有静态资源,在最外一层需要再一个zuul或者nginx去路由。* 通常情况下由nginx做第一层比较好,第二层的一些例如权限等校验交由zuul处理* 路由配置方式: a、path-url方式  b、path-serviceId方式,推荐使用path-serviceId方式,方便后期网关服务维护*/
@SpringBootApplication
@EnableDiscoveryClient
//@EnableZuulProxy注解用于开启Zuul路由功能(反向代理)
@EnableZuulProxy
public class SpringcloudApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudApiGatewayApplication.class, args);}
}

六、application.yml配置路由匹配规则

zuul的路由规则主要有两种配置方式,path-url以及path-serviceId两种方式,但是path-url不利于维护,要具体制定某个服务的url,其实在微服务中,每个服务都注册到eureka服务注册中心上,这个时候其实可以通过serviceId直接找到具体指向的服务。推荐使用path-serviceId方式配置。

server:port: 3333
spring:application:name: api-gateway
eureka:client:service-url:defaultZone: http://localhost:1111/eureka/
#服务路由:推荐使用serviceId方式配置路由,方便后期维护
zuul:routes:zuul-service-url:#通过path/url方式配置路由: 以/zuul-service-url开头的请求都转发到zuul-servicepath: /zuul-service-url/**url: http://localhost:2222/#通过path/serviceId方式配置路由: 以/zuul-service-serviceId开头的请求都转发到zuul-servicezuul-service-serviceId:path: /zuul-service-serviceId/**#对应注册到Eureka中的serviceIdserviceId:  zuul-service
#通过配置以上路由,前台我们访问地址:
# http://localhost:3333/zuul-service-url/getInfo/weixiaohuai
# >>>>>路由到(实际请求的地址)>>>>>
# http://localhost:2222/getInfo/weixiaohuai# http://localhost:3333/zuul-service-serviceId/getInfo/weixiaohuai
# >>>>>路由到(实际请求的地址)>>>>>
# http://localhost:2222/getInfo/weixiaohuai

#通过配置以上路由,前台我们访问地址:

a. path-url方式:

# http://localhost:3333/zuul-service-url/getInfo/weixiaohuai

# >>>>>路由到(实际请求的地址)>>>>>

# http://localhost:2222/getInfo/weixiaohuai

b. path-serviceId方式:

# http://localhost:3333/zuul-service-serviceId/getInfo/weixiaohuai

# >>>>>路由到(实际请求的地址)>>>>>

# http://localhost:2222/getInfo/weixiaohuai

七、启动项目

分别启动eureka-servier、zuul-service、zuul-api-gateway

我们通过浏览器访问

http://localhost:3333/zuul-service-url/getInfo/weixiaohuai

可以看到,网关已经帮我们路由到zuul-service服务,成功返回数据,这是path-url方式。

接着我们访问

http://localhost:3333/zuul-service-serviceId/getInfo/weixiaohuai

可以看到,网关同样帮我们路由到了zuul-service服务,成功返回数据,这是path-serviceId方式。

以上就完成了zuul路由跳转的功能,接下来我们谈谈zuul路由过滤的功能,在实际项目中,通常需要进行权限校验的功能,这里模拟验证url中是否传username以及password参数并且校验是否正确。zuul路由过滤是通过过滤器实现的,通常继承ZuulFilter类,并且实现其中的方法即可。

ZuulFilter中方法的介绍:

a. filterType:指定过滤器的类型,可选择的值有:

pre:在路由之前执行

routing:在路由的时候执行

post:在路由完成之后执行

error:路由发生错误时执行

b. filterOrder:指定过滤器的执行顺序,数字越大,优先级越低

c. shouldFilter:是否需要过滤,return true表示需要执行该过滤器

d. run:过滤器的具体实现逻辑

下面我们创建一个校验用户名的AccessUsernameZuulFilter:

/*** @Title: AccessUsernameZuulFilter* @ProjectName springcloud_zuul_api_gateway* @Description: 校验用户名的Zuul过滤器* @Author WeiShiHuai* @Date 2018/9/14 15:02*/@Component
public class AccessUsernameZuulFilter extends ZuulFilter {private static Logger logger = LoggerFactory.getLogger(AccessUsernameZuulFilter.class);private static final String USER_NAME = "weixiaohuai";/*** 过滤器类型* 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*/@Overridepublic Object run() {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//获取请求url中的usernameString username = request.getParameter("username");//说明用户名不为空且正确if (null != username && USER_NAME.equals(username)) {//表示让Zuul进行路由跳转requestContext.setSendZuulResponse(true);//设置响应码requestContext.setResponseStatusCode(200);logger.info("welcome,the username is valid!!");//记录这个过滤器的状态requestContext.set("isSuccess", true);return null;} else { //用户名不正确//表示让Zuul过滤这个请求,不进行路由跳转requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(401);//记录这个过滤器的状态requestContext.set("isSuccess", false);logger.info("sorry,the username is not valid, please try again!!");requestContext.setResponseBody("sorry,the username is not valid, please try again!!");return null;}}
}

注意:

//表示让Zuul进行路由跳转requestContext.setSendZuulResponse(true);//表示让Zuul过滤这个请求,不进行路由跳转
requestContext.setSendZuulResponse(false);//设置响应码
requestContext.setResponseStatusCode(200);

八、创建校验密码的过滤器AccessPasswordZuulFilter

跟校验用户名的类似,注意在shouldFilter()方法中拿到全局保存的isSuccess变量,由于标识该过滤器是否需要被执行,如果用户名都没校验通过,显然不需要执行密码的校验。

/*** @Title: AccessPasswordZuulFilter* @ProjectName springcloud_zuul_api_gateway* @Description: 校验密码的Zuul过滤器* @Author WeiShiHuai* @Date 2018/9/14 15:37*/@Component
public class AccessPasswordZuulFilter extends ZuulFilter {private static Logger logger = LoggerFactory.getLogger(AccessPasswordZuulFilter.class);private static final String PASSWORD = "123456";/*** 过滤器类型* pre:在路由之前执行  routing:在路由的时候执行  post:在路由完成之后执行  error:路由发生错误时执行** @return*/@Overridepublic String filterType() {return "pre";}/*** 过滤器的执行顺序* 数字越大,优先级越低** @return*/@Overridepublic int filterOrder() {return 1;}/*** 是否需要过滤,true表示过滤,false表示不过滤** @return*/@Overridepublic boolean shouldFilter() {RequestContext requestContext = RequestContext.getCurrentContext();//获取上一个过滤器保存的过滤器状态,如果返回false,则说明上一个过滤器没有成功,则无需执行后面的过滤器,直接返回结果return (boolean) requestContext.get("isSuccess");}/*** 过滤器具体校验逻辑,如权限校验等等* 实际项目中可以进行数据库查询权限数据库等等** @return*/@Overridepublic Object run() {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//获取请求url中的passwordString password = request.getParameter("password");//说明密码不为空且正确if (null != password && PASSWORD.equals(password)) {//表示让Zuul进行路由跳转requestContext.setSendZuulResponse(true);//设置响应码requestContext.setResponseStatusCode(200);//记录这个过滤器的状态requestContext.set("isSuccess", true);logger.info("welcome,the password is valid!!");return null;} else { //用户名不正确//表示让Zuul过滤这个请求,不进行路由跳转requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(401);//记录这个过滤器的状态requestContext.set("isSuccess", false);logger.info("sorry,the password is not valid, please try again!!");requestContext.setResponseBody("sorry,the password is not valid, please try again!!");return null;}}
}

九、启动类注入过滤器Bean

@SpringBootApplication
@EnableDiscoveryClient
//@EnableZuulProxy注解用于开启Zuul路由功能(反向代理)
@EnableZuulProxy
public class SpringcloudApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudApiGatewayApplication.class, args);}@BeanAccessUsernameZuulFilter accessUsernameZuulFilter() {return new AccessUsernameZuulFilter();}@BeanAccessPasswordZuulFilter accessPasswordZuulFilter() {return new AccessPasswordZuulFilter();}
}

十、启动项目

分别启动eureka-server、zuul-service、zuul-api-gateway

我们浏览器访问http://localhost:3333/zuul-service-url/getInfo/weixiaohuai或者http://localhost:3333/zuul-service-serviceId/getInfo/weixiaohuai,如下图

可以看到,如果url中没有传入username或者password参数的话,返回我们自定义的错误信息

a. 如果我们访问http://localhost:3333/zuul-service-url/getInfo/weixiaohuai?username=weixiaohuai,这时候校验用户名的过滤器已经通过,被校验密码的过滤器拦截了,提示密码不合法

b. 如果我们访问http://localhost:3333/zuul-service-url/getInfo/weixiaohuai?password=123456,同样确实username参数,如下图返回用户名不合法的错误

c. 如果我们访问http://localhost:3333/zuul-service-url/getInfo/weixiaohuai?username=weixiaohuai&password=123456,这时候路由就成功跳转到zuul-service中

至此,zuul路由过滤功能已经实现完成。在实际项目中,需要结合权限验证框架进行实现,这里只是演示zuul过滤器的一些用法。本文是作者在学习过程中的一些总结,文章仅供参考,希望大家一起学习,共同进步。

Spring Cloud Zuul路由网关(学习总结)相关推荐

  1. Spring Cloud Zuul API 网关服务

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

  2. Spring Cloud Zuul中使用Swagger汇总API接口文档

    有很多读者问过这样的一个问题: 虽然使用Swagger可以为Spring MVC编写的接口生成了API文档,但是在微服务化之后,这些API文档都离散在各个微服务中,是否有办法将这些接口都整合到一个文档 ...

  3. Spring Cloud Zuul防DDOS攻击

    前一段时间,公司的短信服务经常收到预警,当时初步猜测我们的短信服务受到了攻击,于是想到了两种实现方案. 方案一: 采用nginx防止DDOS(网上有很多案例可以借鉴) 方案二: 采用Spring Cl ...

  4. Spring Cloud Zuul中使用Swagger汇总API接口文档 1

    有很多读者问过这样的一个问题:虽然使用Swagger可以为Spring MVC编写的接口生成了API文档,但是在微服务化之后,这些API文档都离散在各个微服务中,是否有办法将这些接口都整合到一个文档中 ...

  5. 《深入理解 Spring Cloud 与微服务构建》第十章 路由网关 Spring Cloud Zuul

    <深入理解 Spring Cloud 与微服务构建>第十章 路由网关 Spring Cloud Zuul 文章目录 <深入理解 Spring Cloud 与微服务构建>第十章 ...

  6. API 网关服务:Spring Cloud Zuul(二):路由详解、Cookie 与头信息

    实践出于<Spring Cloud 微服务实战> - 瞿永超 著 路由详解 传统路由配置   传统路由配置就是在不依赖于服务发现机制的情况下,通过在配置文件中具体指定每个路由表达式与服务实 ...

  7. SpringCloud学习系列之七 ----- Zuul路由网关的过滤器和异常处理

    前言 在上篇中介绍了SpringCloud Zuul路由网关的基本使用版本,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的路由 ...

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

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

  9. Spring Cloud(四) API网关Zuul

    前文回顾: Spring Cloud(一)Eureka Server-单体及集群搭建 Spring Cloud(二) 配置Eureka Client Spring Cloud(三) 熔断器Hystri ...

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

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

最新文章

  1. 《数据科学:R语言实现》——3.12 估计缺失数据
  2. leetcode两数之和
  3. python logging模块使用教程
  4. linux创建逻辑目录,Linux创建逻辑卷
  5. java canvas旋转_在HTML5 Canvas上将图像旋转90度
  6. openssh 加固
  7. 【优化算法】社会群体优化算法(SGO)【含Matlab源码 1449期】
  8. android 执行Shell命令
  9. 【实习之T100开发】帆软报表笔记
  10. ExtremeComponents源码解析(一)
  11. 最最简单的使用DW编程软件
  12. 菜鸟学R语言(方差分析)
  13. F.dropout()与nn.dropout()
  14. 盛迈坤电商:店铺推广的技巧分享
  15. 纯css3卡通火龙果
  16. [Python]安装/升级pip/pip3
  17. 禁止win7系统flash插件自动更新教程【系统天地】
  18. Content-Type四种常见取值application/x-www-form-urlencoded,multipart/form-data,application/json,text/xml
  19. 【ThreeJS基础教程-初识Threejs】1.3 右手坐标系
  20. Python数据处理与分析小项目-分析员工过早离职原因

热门文章

  1. 怎么看蛋白质编码序列_墨鱼的“墨汁”可以吃吗,它有什么营养?看完就明白,涨知识了...
  2. Otsu‘s Thresholding的工作原理
  3. C/C++[PAT B1022]D进制的A+B
  4. python append和extend_Python中append和extend区别
  5. 对于Y=Hx的H细节的一些讨论
  6. NLP系列(2)_用朴素贝叶斯进行文本分类(上)
  7. python urllib2详解及实例
  8. 【OpenGL 实验一】图元的生成+区域填充
  9. linux内核event原理,linux epoll epoll的原理;struct epoll_event 为什么要这样设计
  10. 攻防世界 ics-05 write up