在微服务架构中,网关(Gateway)是一个提供统一访问地址的组件,它充当了客户端和内部微服务之间的中介网关主要负责流量路由和转发,将外部请求引导到相应的微服务实例上,同时提供一些功能,如身份认证、授权限流、监控、日志记录等。
网关的主要作用有以下几个:
1.路由功能:网关可以根据目标地址的不同,选择最佳的路径将数据包从源网络路由到目标网络。它通过维护路由表来确定数据包的转发方向,并选择最优的路径
2.安全控制(统一认证授权):网关可以实施网络安全策略,对进出的数据包进行检查和过滤。它可以验证和授权来自源网络的数据包,并阻止未经授权的访问。防火墙是一种常见的网关设备,用于过滤和保护网络免受恶意攻击和未经授权的访问。
3.协议转换:不同网络使用不同的通信协议,网关可以进行协议转换,使得不同网络的设备可以互相通信。例如,例如将HTTPS 协议转换成HTTP 协议
4.网络地址转换(NAT):网关还可以执行网络地址转换,将内部网络使用的私有IP 地址转换为外部网络使用的公共 IP 地址,以实现多台计算机共享一个公共 IP 地址出去上网。
1.路由(Route):定义了请求应该被转发到哪个目标地址。路由由 ID、目标URI、断言和过滤器组成。通过配置多个路由,可以实现不同请求的路由规则。
2.断言(Predicate): 用于匹配请求的条件,如果请求匹配断言条件,则会被路由到对应的目标地址。断言可以基于请求的路径、请求头、请求参数等信息进行匹配。也就是说,可以在断言里面写一套规则,如果发送过来的请求满足这个规则,就可以进行路由功能
3.过滤器 (Filter):用于在请求路由前或路由后进行一些处理,如添加头部信息、修改请求体等。过滤器可以在全局范围或特定路由范围内配置,多个过滤器可以组成过滤器链。
步骤:
1.添加Gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.设置网关路由规则
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
server:
port: 10086
下面为我各模块的代码
gateway-demo
application.yml
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**
server:
port: 10086
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>gateway-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-service</name>
<description>gateway-service</description>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-gateway-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.gatewayservice.GatewayServiceApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
其他均为创建时候的样子
UserController
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getname")
public String genName(){
return "UserService:name=java-"+new Random().nextInt(10);
}
}
application.yml
server:
port: 9090
pom.xml
<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.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>user-serviceartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>user-servicename>
<description>user-servicedescription>
<parent>
<groupId>com.examplegroupId>
<artifactId>spring-cloud-gateway-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>17source>
<target>17target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.example.userservice.UserServiceApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
其他不动
父模块
pom.xml
<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.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>spring-cloud-gateway-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>spring-cloud-gateway-demoname>
<description>spring-cloud-gateway-demodescription>
<packaging>pompackaging>
<modules>
<module>user-servicemodule>
<module>gateway-servicemodule>
modules>
<properties>
<java.version>17java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>3.0.2spring-boot.version>
<spring-cloud.version>2022.0.0spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>17source>
<target>17target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
project>
这里模拟user-service为内网,通过gateway-service访问内网
注意:Spring Web框架和Gateway框架不能同时使用,因为Gateway已经内置了web了\
直接用英文的逗号
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090
predicates:
- Path=/user/**,/userlog/**
server:
port: 10086
不能
- Path=/user/**
- Path=/userlog/**
1.After:请求在指定时间之后才匹配
2.Before: 请求在指定时间之前才匹配
3.Between:请求在指定时间中间才匹配
4.Cookie: 配置请求中的 Cookie 值
5.Header:配置请求中的 Header 值
6.Host:匹配请求头中的 Host 值
7.Method: 匹配请求头中的 Method 的值
8.Path:匹配请求路径
9.Query: 匹配请求参数
10.RemoteAddr:匹配请求的 I 地址,支持IPV4 和IPV6
11.Weight:根据权重来分发请求,权重根据 group 来计算
12.XForwardedRemoteAddr: 根据 X-Forwarded-For 匹配
具体使用详情请看官方文档:点这里
在不借助其他组件的情况下,主要有
1.权重路由分发
2.限流(和Redis一起使用,令牌桶限流算法)
3.请求重试功能
(这里不需要OpenFeign和SpringWeb,因为Gateway都实现了)
1.添加依赖
在gateway-service的pom.xml底下添加这三个依赖
在user-service的pom.xml低下也要加nacos依赖
2.配置nacos
user-service的配置文件
server:
port: 0
spring:
application:
name: user-service-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
gateway-service的配置文件
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
gateway:
routes:
- id: userservice
uri: lb://user-service-gateway
predicates:
- Path=/user/**,/userlog/**
#- id: user-service
# uri: http://localhost:9090
#predicates:
# - Weight=group1,10
#- id: user-service2
# uri: http://localhost:9092
#predicates:
# - Weight=group1,90
# - id: userservice
# uri: http://localhost:9090
#predicates:
# - Path=/user/**
#- id: orderservice
# uri: http://localhost:9091
#predicates:
# - Path=/order/**
server:
port: 10086
上述三个组件配合的逻辑为
1.启动了user-service服务之后,这个服务就被注册到了nacos了
2.当我的前端通过网站访问localhost:10086/user/gatname的时候,走网关,网关的lb://user-service-gateway这个配置中的 lb 就是走了负载均衡器,后面的就是让负载均衡器去找注册中心名叫user-service-gateway的服务
3.找到了这个服务之后,把这个服务中的实例轮询的显示在前端页面上
通俗的说就是当数据经过网关的时候,过滤器可以根据实际应用,来把你的数据修改、删除、屏蔽
1.请求修改:过滤器可以修改进入的 HTTP 请求,例如添加、删除或修改请求头和请求参数。
2.路由决策:过滤器可以用于改变请求的路由。例如,根据请求的特定属性将请求重定向到不同的后端服务。
3.响应修改:过滤器也可以修改从后端服务发出的响应,如修改响应头或处理响应数据。
4.安全性:过滤器可用于实现安全相关的功能,如身份验证和授权、防止跨站点请求伪造(CSRF)等。
5.日志记录和监控:过滤器可以用于记录请求和响应的详细信息,对服务进行监控和度量,以便于调试和性能分析。
6.限流和熔断:通过过滤器实现请求的限流和熔断,保护系统免受过高流量的影响。
7.负载均衡:过滤器可以结合负载均衡器使用,将请求均衡地分配到多个后端实例。
8.重试和回退逻辑:在后端服务失败的情况下,过滤器可以实现请求的重试或提供回退响应。
9.请求和响应的压缩或解压缩:在请求到达后端服务之前或在响应返回给客户端之前,过滤器可以对数据进行压缩或解压缩。
首先,过滤器有38个,使用方法请看上述断言的那个网站
1.内置过滤器:(上述的38个使用方法去官网看,比我写的更权威)
1.1局部的内置过滤器:你的过滤器只在一个服务有用
1.2全局的内置过滤器:你的过滤器在注册到nacos的所有服务都有用
如果一个服务既有全局又有局部,那就会有两个信息,不会覆盖
2.自定义过滤器
下面来写一个登陆验证的过滤器
第一步:继承GlobalFilter
第二步:重写filter方法
第三步:注入IoC容器中
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class AuthFilter implements GlobalFilter {
@Override
//Mono表示下一步要执行的事件
public Mono<Void> filter(ServerWebExchange exchange, //执行的事件
GatewayFilterChain chain) //过滤器链
{
ServerHttpRequest request= exchange.getRequest();
ServerHttpResponse response= exchange.getResponse();
String username=request.getQueryParams().getFirst("username");
String password=request.getQueryParams().getFirst("password");
if(username!=null&&username.equals("admin")&&password!=null&&password.equals("admin")){
//已经登录,执行下一步
return chain.filter(exchange);
}
return response.setComplete();//没通过验证,不用执行下一步了
}
}
当一个请求到达 Spring Cloud Gateway 时,Gateway 会根据定义的路由规则进行匹配。这一过程包括对请求进行断言判断。如果请求与某个路由的断言相匹配,这个请求就会沿着这个路由转发。在请求被转发到具体服务之前,可以应用一系列的前置过滤器来处理请求。这些过滤器可以修改请求,或者完全拒绝它。如果请求被接受处理,它会被转发到对应的微服务。微服务处理完请求后,其响应会返回到网关。在响应返回给客户端之前,可以应用一系列的后置过滤器来处理响应。
Spring Cloud Gateway不支持注册服务为下划线(“_”)的方式,比如user_service,因此在注册到注册中心的过程中不要使用下划线,要使用的话,当你需要用这个服务的时候代码会找不到这个服务的,要用中划线,比如:user-service。