正文
一、什么是网关?
网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。同层--应用层。-----摘自《百度百科》
二、Spring Cloud Gateway 原理
参考官网spring-cloud-gateway
三、构建简单的网关项目
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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xiaojie</groupId> <artifactId>xiaojie-gateway</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> </parent> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2021.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2021.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.0.2</version> </dependency> <!-- Feign Client for loadBalancing --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.0.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.0.2</version> </dependency> <!-- Feign Client for loadBalancing --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!-- mysql 依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 阿里巴巴数据源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core --> <dependency> <groupId>com.github.vladimir-bukhtoyarov</groupId> <artifactId>bucket4j-core</artifactId> <version>6.0.1</version> </dependency> </dependencies> </project>
启动类和简单api省略
四、路由谓词工厂
server: port: 80 spring: application: name: xiaojie-gateway cloud: gateway: routes: # - id: test_route # uri: https://www.baidu.com/ # filters: # #这个意思是截取第一个前缀后访问 比如,请求/name/bar/foo,去除掉前面一个前缀之后,最后转发到目标服务的路径为/bar/foo # - StripPrefix=1 # predicates: # - Path=/test #路径拦截 # #ZonedDateTime dateTime = ZonedDateTime.now(); java8之后ZonedDateTime时间 # - After=2021-07-14T09:51:55.052+08:00[Asia/Shanghai] #- Before=2021-07-15T09:51:55.052+08:00[Asia/Shanghai] #- Between=2021-07-14T09:51:55.052+08:00[Asia/Shanghai],2021-07-15T09:51:55.052+08:00[Asia/Shanghai] #- Cookie=xiaojie, [a-z] #匹配cookie名字满足后面表达式的时候 #- Header=X-Request-Id, \d+ # 匹配请求头中X-Request-Id 为数字的 #- Host=**.xiaojie.com #匹配域名路由 #- Method=GET,POST #拦截方法是get post 的请求 #- Query=red, gree. #如果请求包含red其值与正则gree.表达式匹配的查询参数,则前面的路由匹配,因此green和greet将匹配 #- RemoteAddr=192.168.1.1/24 #匹配ip #一下是权重路由匹配 - id: weight_high uri: https://www.baidu.com predicates: - Weight=group1, 8 - id: weight_low uri: https://www.sina.com predicates: - Weight=group1, 2
五、网关集群
通过Nginx转发到网关服务,网关经过轮训算法,或者其他的算法,转发到真实的服务器,进行服务的访问,下面开始配置。
网关端的配置文件
server: port: 82 ####服务网关名称 spring: application: name: xiaojie-gateway cloud: gateway: ###路由策略 routes: ###根据我们的服务名称查找地址实现调用 - id: member #uri: http://127.0.0.1:8090 uri: lb://xiaojie-member/ #服务的名称 filters: - StripPrefix=1 ###匹配规则 predicates: - Path=/member/** #开启服务注册中心获取服务 discovery: locator: enabled: true nacos: discovery: #注册地址 server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 #是否开启nacos注册 enabled: true #账号 username: xiaojie #密码 password: nacos #命名空间 ,一定要对应上自己注册的服务的命名空间 namespace: 28eb29ea-5a04-4714-8ae8-77d37c01166a #分组 group: DEV_GROUP
会员服务端的配置文件
spring: application: name: xiaojie-member cloud: nacos: config: #前缀 prefix: xiaojie-member #地址 server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 #扩展名 file-extension: yaml #命名空间 namespace: 28eb29ea-5a04-4714-8ae8-77d37c01166a #分组 group: DEV_GROUP #开关 enabled: true #动态刷新配置 refresh-enabled: true discovery: #注册地址 server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 #是否开启nacos注册 enabled: true #账号 username: xiaojie #密码 password: nacos #命名空间 namespace: 28eb29ea-5a04-4714-8ae8-77d37c01166a #分组 group: DEV_GROUP
Nginx添加如下配置
upstream xiaojie_gateway{ server 127.0.0.1:81; server 127.0.0.1:82; } server { listen 80; server_name gateway.xiaojie.com; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://xiaojie_gateway; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
在网关中添加以下filter
package com.xiaojie.filter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * @Description: 配置token过滤器 * @author: xiaojie * @date: 2021.07.14 */ @Component @Slf4j public class TokenFilter implements GlobalFilter { @Value("${server.port}") private String serverPort; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //获取参数 String token = exchange.getRequest().getQueryParams().getFirst("token"); if(!StringUtils.hasText(token)){ //token为空转发到其他的地址 ServerHttpResponse response = exchange.getResponse(); // response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); String msg = "token not is null "; DataBuffer buffer = response.bufferFactory().wrap(msg.getBytes()); return response.writeWith(Mono.just(buffer)); } // 在请求头中存放serverPort serverPort ServerHttpRequest request = exchange.getRequest().mutate().header("serverPort", serverPort) .build(); log.info("端口号是...............{}"+serverPort); return chain.filter(exchange.mutate().request(request).build()); } }
访问http://gateway.xiaojie.com/member/getMember?token=456 可以看到实现了集群效果。