zuul叫路由网关,它包含对请求的路由和过滤的功能。
路由负责将外部的请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。而过滤是负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能基础。
源代码:https://github.com/zhongyushi-git/cloud-zuul.git
1)参考ribbon的项目新建一个项目cloud-zuul,把eureka集群、api以及服务提供者8001拿过来
2)在pom中导入依赖
<!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--eureka-client--> <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>
3)配置yml
server: port: 9527 spring: application: name: cloud-zuul-gateway #把客户端注册到服务列表中 eureka: client: #表示是否将自己注册进EurekaServer默认为true register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetch-registry: true service-url: defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/ #设置入驻的服务的名称,是唯一的 instance: instance-id: gateway-9527.com #访问路径显示ip prefer-ip-address: true
4)在hosts文件添加映射
127.0.0.1 myzuul.com
5)在com.zys.cloud包下创建启动类并添加注解@EnableZuulProxy
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableZuulProxy public class ZuulMain9527 { public static void main(String[] args) { SpringApplication.run(ZuulMain9527.class, args); } }
6)启动测试
先启动eureka集群,然后启动微服务提供者8001,最后启动路由9527。
不用路由访问:http://localhost:8001/user/get/1
使用路由访问: http://myzuul.com:9527/cloud-provider/user/get/1,其中cloud-provider是微服务提供者的名称
在使用路由访问的时候,暴露出了微服务的名称,但是一般情况下是不会这样做的,因此需要对微服务名称进行代理。
7)配置服务代理
在路由的yml配置代理的名称并设置不能使用微服务名进行访问。
#配置微服务代理 zuul: routes: #指定要代理的微服务名称 myuser.serviceId: cloud-provider #指定代理的路径 myuser.path: /myuser/** #忽略真实的服务名,即不能使用服务名访问,只能通过代理访问以保证安全 #忽略单个微服务 ignored-services: cloud-provider #批量忽略微服务 # ignored-services: "*"
重启路由的服务,访问http://myzuul.com:9527/myuser/user/get/1是没有问题的,访问http://myzuul.com:9527/cloud-provider/user/get/1出现404,已达到效果。
实例中设置忽略了单个微服务,如果要批量忽略微服务,给ignored-services设置为"*"即可。
8)设置统一前缀
有时候多个系统之间访问的路径需要相同的前缀,这个时候只需要在yml配置即可。
zuul:
#设置统一的前缀
prefix: /springcloud
然后访问的时候都需要加这个前缀,访问路径是http://myzuul.com:9527/springcloud/myuser/user/get/1。
旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤功能,如熔断、限流、重试等。三大核心概念如下:
Route(路由):是构建网关的基本模块,由ID、URL、一系列断言和过滤器组成。
Predicate(断言):用于匹配Http请求中的所有内容,如果匹配则进行路由。
Filter(过滤):指的是Spring框架中GatewayFilter的实例
它是基于WebFlux框架实现的,而WebFlux框架底层使用了高性能的Reactor模式通信框架Netty,是基于异步非阻塞模型开发的。而zuul使用的是阻塞框架。
源代码:https://github.com/zhongyushi-git/cloud-gateway.git
1)创建maven的父工程cloud-gateway,导入依赖
<!--统一管理jar包版本--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> </properties> <!-- 依赖管理,父工程锁定版本--> <dependencyManagement> <dependencies> <!--spring boot 2.2.2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud Hoxton.SR1--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build>
2)创建eureka服务子模块cloud-eureka-server7001,导入依赖
<dependencies> <!--eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!--boot web actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
3)eureka的yml配置
server: port: 7001 eureka: instance: #eureka服务端的实例名称 hostname: localhost client: #false表示不向注册中心注册自己 register-with-eureka: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4)创建eureka启动类
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } }
5)创建服务提供者子模块cloud-provider8001,导入依赖
<dependencies> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--boot web actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
6)8001的yml配置
server: port: 8001 spring: application: name: cloud-provider #把客户端注册到服务列表中 eureka: client: #表示是否将自己注册进EurekaServer默认为true register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka/ #设置入驻的服务的名称,是唯一的 instance: instance-id: cloud-provider8001 #访问路径显示ip prefer-ip-address: true
7)创建8001启动类
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
8)创建8001的controller接口
package com.zys.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import java.util.Date; @RestController @RequestMapping("/user") public class UserController { @Value("${server.port}") private String port; @Value("${eureka.client.service-url.defaultZone}") private String eureka; @GetMapping("/get") public String get(){ return "server port is \t"+port+".\t\t\t\t time:"+new Date(); } @GetMapping("/get2") public String get2(){ return "eureka server is \t"+eureka+".\t\t\t\t time:"+new Date(); } }
9)创建服务提供者子模块cloud-provider8002,方式同8001,只是端口号不同。创建完成后先启动eureka,然后启动8001和8002,在浏览器测试接口。
1)导入依赖
<dependencies> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>
需要注意的是,这里不需要导入web。
2)yml配置
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: #开启从注册中心动态创建路由的功能,利用微服务名进行路由 discovery: locator: enabled: true routes: - id: provider_routh #路由的ID,没有固定规则但要求唯一,简易配合服务名 uri: lb://cloud-provider #匹配后提供服务的路由地址,根据服务名访问 predicates: - Path=/user/get/** #断言,路径相匹配的进行路由 - id: provider_routh #路由的ID,没有固定规则但要求唯一,简易配合服务名 uri: lb://cloud-provider #匹配后提供服务的路由地址 predicates: - Path=/user/get2/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service instance-id: cloud-gateway #访问路径显示ip prefer-ip-address: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka/
3)创建启动类
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class GatewayMain9527 { public static void main(String[] args) { SpringApplication.run(GatewayMain9527.class,args); } }
4)启动测试
先启动eureka,然后启动8001和8002,最后启动9527。浏览器输入http://127.0.0.1:9527/user/get2就可以正常访问了。多刷新几次,可以看出是8001和8002轮询的。
除了2.3.2中使用yml的方式配置路由外,还可以通过编码方式配置。
新建配置类GateWayConfig
package com.zys.cloud.config; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 编码方式配置路由 */ @Configuration public class GateWayConfig { /** * 配置一个id为route-name的路由规则, * 当访问地址http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei * @param routeLocatorBuilder * @return */ @SuppressWarnings("JavaDoc") @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); routes.route("path_route1", r -> r.path("/guonei") .uri("http://news.baidu.com/guonei")).build(); return routes.build(); } }
重启9527,访问地址http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei。
有时候为了进行配置,就可以配置断言。
例如:配置get2请求在某个时间后生效。只需要在yml的predicates设置After即可。
predicates: - Path=/user/get2/** #断言,路径相匹配的进行路由 - After=2020-04-09T21:15:28.872+08:00[Asia/Shanghai]
后面的时间格式必须正确,获取格式时间的方法
public static void getTime(){ ZonedDateTime zbj = ZonedDateTime.now(); System.out.println(zbj); }
又如设置请求的方法必须为get
predicates: - Path=/user/get2/** #断言,路径相匹配的进行路由 - After=2020-04-09T21:15:28.872+08:00[Asia/Shanghai] - Method=GET
自定义一个过滤器,只有在请求中包含unmae且不为null时才能访问。创建过滤器类MyLogGateWayFilter
package com.zys.cloud.filter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * 自定义过滤器 */ @Component public class MyLogGateWayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //每次进来后判断带不带uname这个key String uname = exchange.getRequest().getQueryParams().getFirst("uname"); //uname为null非法用户 if(uname == null){ exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
重启9527,访问地址http://127.0.0.1:9527/user/get2时无法访问,而http://127.0.0.1:9527/user/get2?uname=1可以正常访问。
原文:https://www.cnblogs.com/zys2019/p/12656029.html