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: 8087
spring:
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
application:
name: gateway
最后,我们在启动类上添加@EnableDiscoveryClient注解。
@SpringBootApplication @EnableDiscoveryClient public 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: 8087
spring:
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,abc
application:
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,如果没有则拦截并报错。
@Component public 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的使用: )
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!