1d95vIKJSn9 发表于 2025-2-25 12:43:37

nacos(七): gateway(单体)

这篇文章将从gateway的搭建、自动路由匹配、路由数组、跨域和路由过滤器五个方面对gateway项目展开讨论。
1、gateway的搭建
gateway的项目基本的搭建过程与消费者的搭建过程基本一致,细节部分可参考《nacos(四): 创建第一个消费者Conumer(单体)》。
搭建完成后,在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>    <version>0.0.1-SNAPSHOT</version>    <artifactId>gateway</artifactId>    <packaging>jar</packaging>    <properties>      <java.version>1.8</java.version>      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>      <spring-boot.version>2.7.6</spring-boot.version>      <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>    </properties>    <dependencies>      <!-- 服务发现-->      <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>            <version>3.1.5</version>      </dependency>      <!--⽹关-->      <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-gateway</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.boot</groupId>                <artifactId>spring-boot-dependencies</artifactId>                <version>${spring-boot.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>            <dependency>                <groupId>com.alibaba.cloud</groupId>                <artifactId>spring-cloud-alibaba-dependencies</artifactId>                <version>${spring-cloud-alibaba.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>2021.0.5</version>                <type>pom</type>                <scope>import</scope>            </dependency>      </dependencies>    </dependencyManagement>    <build>      <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.8.1</version>                <configuration>                  <source>1.8</source>                  <target>1.8</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.gateway.GatewayApplication</mainClass>                  <skip>false</skip>                </configuration>                <executions>                  <execution>                        <id>repackage</id>                        <goals>                            <goal>repackage</goal>                        </goals>                  </execution>                </executions>            </plugin>      </plugins>    </build></project>
注意:在gateway项目中,不能引入spring mvc或者start web类的关于web的依赖,否则会报错“Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway.”。
另外,gateway的版本也需要进行匹配,在前几篇文章中,我们也一再强调微服务项目对于库的版本要求非常精细。版本稍微不一致可能会报出奇怪的问题,比如”Error processing condition on org.springframework.cloud.gateway.config.GatewayAutoConfiguration.propertiesRouteDefinitionLocator“。
 
接下来,在application.yml中,开启自动路由匹配:
server:port: 8087spring:cloud:    nacos:      discovery:      server-addr: 127.0.0.1:8848      username: nacos      password: nacos      config:      server-addr: 127.0.0.1:8848      file-extension: properties      username: nacos      password: nacos    loadbalancer:      nacos:      enabled: true    gateway:      discovery:      locator:          enabled: trueapplication:    name: gateway
 
最后,我们在启动类上添加@EnableDiscoveryClient注解。
@SpringBootApplication@EnableDiscoveryClientpublic class GatewayApplication {    public static void main(String[] args) {      SpringApplication.run(GatewayApplication.class, args);    }}
 
配置完成后,启动gateway,可以看到nacos的管理后台里gateway已经注册成功。

 
2、路由自动匹配
在文章的第1部分里,application.yml中开启的路的自动匹配功能。
如个例子:
当前在nacos中有一个product1服务,服务提提供了/hello的地址。
通过gateway,我们可以访问http://127.0.0.1:8087/product1/hello,通过gateway访问到product1的hello地址。如下图:

其中:
127.0.0.1:8087:分别是gateway的IP地址和端口号;
product1: 是注册在nacos的里的服务名;
/hello:则是product1服务提供的资源地址。
 
3、路由数组
在application.yml中配置routes配置节,可开启路由数组,如下
server:port: 8087spring:cloud:    nacos:      discovery:      server-addr: 127.0.0.1:8848      username: nacos      password: nacos      config:      server-addr: 127.0.0.1:8848      file-extension: properties      username: nacos      password: nacos    loadbalancer:      nacos:      enabled: true    gateway:      discovery:      locator:          enabled: true      routes:      - id: product1_hello          uri: lb://product1    # 指的是从nacos中按照名称获取微服务,并遵循负载均衡策略          order: 1    # 路由优先级 数字越低优先级越高          predicates:    # 断言            - Path= /p1/**   # 当请求路径满⾜Path指定的规则时,才进⾏路由换发          filters:            - StripPrefix=1    # 拼接好url之后去掉1层路径也就是p1      - id: order_route          uri: lb://server-order          order: 1          predicates:            - Path=/order/**          filters:            - StripPrefix=1            - AddRequestHeader=msg,abcapplication:    name: gateway
上面的这个配置文件例子中,路由数组里配置了两个路由。各项配置的具体配置的意义,看文件中的注释。其中- StripPrefix=1配置项需要注意。
这一项的意思是,当用户访问http://127.0.0.1:8087/p1/hello,因为/p1/路径触发了第一个路由规则,路由去掉p1这一项,重新拼接为lb://product1/hello去获取访问的结果。
 
断言proeicates还有如果规则可以使用:

 过滤器filters还有如下规则可以使用:

 
4、跨域
可以通过对application.yml的配置进行跨域项的设置,如下:
spring:cloud:    gateway:      globalcors: # 全局的跨域处理      add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题      corsConfigurations:          '[/**]':            allowedOrigins: # 允许哪些⽹站的跨域请求            - "http://localhost:8090"            allowedMethods: # 允许的跨域ajax的请求⽅式            - "GET"            - "POST"            - "DELETE"            - "PUT"            - "OPTIONS"            allowedHeaders: "*" # 允许在请求中携带的头信息            allowCredentials: true # 是否允许携带cookie            maxAge: 360000 # 这次跨域检测的有效期
 
5、路由过滤器
gateway也可以自定义自己的filter,下面用两个例子来说明过如何自定义filter。
示例一:判断请求参数中是否有authorization, authorization参数值是否为admin。如果同时满⾜则放⾏,否则拦截。
@Component@Order(-1) // 用来控制优先级 数字越小优先级越高public class AuthorizeFilter implements GlobalFilter {    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {      String token = exchange.getRequest().getHeaders().get("authorization").get(0);      if (token.equals("admin")){            //            放行            return chain.filter(exchange);      }      //      拦截 禁止访问      exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);      return exchange.getResponse().setComplete();}
示例二:判断请求参数中是否有token,如果没有则拦截并报错。
@Componentpublic class TokenFilter implements GlobalFilter, Ordered {    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {      ServerHttpRequest req= exchange.getRequest();      ServerHttpResponse resp= exchange.getResponse();      MultiValueMap<String, String> params= req.getQueryParams();      if(!params.containsKey("token")){            //输出错误信息            Map<String, Object> map = new HashMap<>();            map.put("msg", "Not Logged in!!!!");            map.put("code", 4000); /*            //3.3作JSON转换         byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8            );            //3.4调用bufferFactory方法,生成DataBuffer对象            DataBuffer buffer = response.bufferFactory().wrap(bytes);*/            //4.调用Mono中的just方法,返回要写给前端的JSON数据            DataBuffer buffer =resp.bufferFactory().wrap("error".getBytes(StandardCharsets.UTF_8));            return resp.writeWith(Mono.just(buffer));      }      return chain.filter(exchange);    }    @Override    public int getOrder() {      return 0;    }}
 
本文关于gateway的内容到这里就结束了,下一篇我们将一起讨论哨兵sentinel的使用: )
 
页: [1]
查看完整版本: nacos(七): gateway(单体)