8 网关路由
8.1 问题引出
- 由于每个微服务都有不同的地址或端口,入口不同,会导致:
- 请求不同数据时要访问不同的入口,需要维护多个入口地址,麻烦;
- 前端无法调用nacos,无法实时更新服务列表;
- 单体架构时只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,这就存在一些问题:
- 每个微服务都需要编写登录校验、用户信息获取的功能吗?
- 当微服务之间调用时,该如何传递用户信息?
- 以上问题都可以通过网关技术解决,即:
- 网关路由,解决前端请求入口的问题;
- 网关鉴权,解决统一登录校验和用户信息获取的问题;
- 统一配置管理,解决微服务的配置文件重复和配置热更新问题。
8.2 认识网关
-
什么是网关?顾明思议,网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验;
-
更通俗的来讲,网关就像是以前园区传达室的大爷
- 外面的人要想进入园区,必须经过大爷的认可,如果你是不怀好意的人,肯定被直接拦截;
- 外面的人要传话或送信,要找大爷。大爷帮你带给目标人;
-
现在,微服务网关就起到同样的作用。前端请求不能直接访问微服务,而是要请求网关:
- 网关可以做安全控制,也就是登录身份校验,校验通过才放行;
- 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去;
-
在SpringCloud当中,提供了两种网关实现方案:
- Netflix Zuul:早期实现,目前已经淘汰
- SpringCloud Gateway:基于 Spring 的 WebFlux 技术,完全支持响应式编程,吞吐能力更强;
8.3 快速入门
- 由于网关本身也是一个独立的微服务,因此也需要创建一个模块开发功能。大概步骤如下:
- 创建网关微服务
- 引入SpringCloud Gateway、Nacos Discovery依赖
- 编写启动类
- 配置网关路由
8.3.1 创建项目
-
在hmall下创建一个新的module,命名为
hm-gateway
,作为网关微服务:
8.3.2 引入依赖
-
在
hm-gateway
模块的pom.xml
文件中引入依赖:- 如果下面代码中的网关依赖报错,右键 >> Maven >> 重新加载项目;
<?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"> <parent> <artifactId>hmall</artifactId> <groupId>com.heima</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>hm-gateway</artifactId> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!--common--> <dependency> <groupId>com.heima</groupId> <artifactId>hm-common</artifactId> <version>1.0.0</version> </dependency> <!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos discovery--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
8.3.3 启动类
-
在
hm-gateway
模块的com.hmall.gateway
包下新建一个启动类:package com.hamll.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
8.3.4 配置路由
-
在配置路由之前,将
hm-server
中的 SearchController 复制到item-server
中: -
在
hm-gateway
模块的resources
目录新建一个application.yaml
文件,内容如下:server: port: 8080 spring: application: name: gateway cloud: nacos: server-addr: 192.168.184.138:8848 gateway: routes: # 定义了一个ID为"item"的路由规则,将匹配/items/**和/search/**路径的请求通过负载均衡方式转发到名为"item-service"的服务 - id: item # 路由规则id,自定义,唯一 uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表 predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务 - Path=/items/**,/search/** # 这里是以 controller 中的请求路径作为判断规则 - id: cart uri: lb://cart-service predicates: - Path=/carts/** - id: user uri: lb://user-service predicates: - Path=/users/**,/addresses/** - id: trade uri: lb://trade-service predicates: - Path=/orders/** - id: pay uri: lb://pay-service predicates: - Path=/pay-orders/**
8.3.5 测试
-
启动:
-
以 http://localhost:8080 拼接微服务接口路径来测试。例如:http://localhost:8080/items/page?pageNo=1&pageSize=1
-
此时,启动UserApplication、CartApplication,然后打开前端页面,发现相关功能都可以正常访问了。
8.4 路由属性
-
路由规则的定义语法如下:
spring: cloud: gateway: routes: - id: item # 路由规则id,自定义,唯一 uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表 predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务 - Path=/items/**,/search/** # 这里是以请求路径作为判断规则
id
:路由的唯一标示uri
:路由目标地址。lb://
代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问predicates
:路由断言,判断请求是否符合当前路由- 可以再添加一个
filters
:路由过滤器,对请求或响应做特殊处理
-
SpringCloud Gateway中支持的断言类型有很多:
名称 说明 示例 After 是某个时间点后的请求 - After=2037-01-20T17:42:47.789-07:00[America/Denver] Before 是某个时间点之前的请求 - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] Between 是某两个时间点之前的请求 - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] Cookie 请求必须包含某些cookie - Cookie=chocolate, ch.p Header 请求必须包含某些header - Header=X-Request-Id, \d+ Host 请求必须是访问某个host(域名) - Host=.somehost.org,.anotherhost.org Method 请求方式必须是指定方式 - Method=GET,POST Path 请求路径必须符合指定规则 - Path=/red/{segment},/blue/** Query 请求参数必须包含指定参数 - Query=name, Jack或者- Query=name RemoteAddr 请求者的ip必须是指定范围 - RemoteAddr=192.168.1.1/24 weight 权重处理 -
Gateway 提供了33种路由过滤器,每种都有独特的作用:
名称 说明 示例 AddRequestHeader 给当前请求添加一个请求头 AddRequestHeader=headerName,headerValue
RemoveRequestHeader 移除请求中的一个请求头 RemoveRequestHeader=headerName
AddResponseHeader 给响应结果中添加一个响应头 AddResponseHeader=headerName,headerValue
RemoveResponseHeader 从响应结果中移除一个响应头 RemoveResponseHeader=headerName
RewritePath 请求路径重写 RewritePath=/red/?(?<segment>.*), /$\{segment}
StripPrefix 去除请求路径中的N段前缀 StripPrefix=1
,则路径/a/b
转发时只保留/b
……