最新版本SpringCloud Gateway网关入门(一)


  • 背景

  • SpringCloud Gateway 简介

  • Gateway入门搭建

    • 1. 创建一个SpringBoot 项目

    • 2. 添加依赖

    • 3. 配置路由转发

    • 4. 添加请求`log` `Filter`

    • 5. 搭建测试服务

    • 测试


背景

接上次线上Spring Boot 和Spring Cloud、Spring Cloud Alibaba版本如何选择以及Zuul和Gateway请求IO模型比对(WebFlux优势)以及Reactor模型分析

选定微服务中网关使用Gateway,接下来我们先搭建一个简单的网关使用

SpringCloud Gateway 简介

github地址: https://github.com/spring-cloud/spring-cloud-gateway

官网文档地址: https://spring.io/projects/spring-cloud-gateway#learn

SpringCloud GatewaySpring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

说人话为什么需要网关呢?我们来想想没有网关我们有多个服务需要做什么?

首先我们的客户端流量入口调用之间的关系可能是这样的

最新版本SpringCloud Gateway网关入门(一)
image-20211208192800542

这样会存在什么问题呢?

  1. 如果添加鉴权功能,需要对每一个服务进行改造
  2. 跨域问题需要对每一个服务进行改造
  3. 跨域问题需要对每一个服务进行改造
  4. 灰度发布、动态路由需要对每一个服务进行改造
  5. 存在安全问题。每个微服务暴露的 Endpoint是固定的,客户端访问需要清楚各个微服务真实的Endpoint

如果我们在服务前添加一层网关作为所有流量的入库,整个架构就变成如下方式

最新版本SpringCloud Gateway网关入门(一)
image-20211208193231907

然后上面所有的问题都可以在网关统一实现,各个服务就无需再实现

Gateway入门搭建

1. 创建一个SpringBoot 项目

2. 添加依赖

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wh</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>gateway</description>


    <properties>
        <Java.version>11</java.version>
        <spring-cloud.version>2020.0.1</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>



    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-gateway-spring-boot-starter </artifactId>
            <version>1.3.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3. 配置路由转发

  • Application.yml
server:
  port: 8080
spring:
  application:
    name: gate-way
  cloud:
    gateway:
      routes:
        - id: plutus_route
          uri: http://localhost:10080
          predicates:
            - Path=/plutus/**

这里简单的配置了一下网关的启动端口为8080,然后配置了一个路由规则

这里配置的路由规则就是 拦截所有请求路径前缀为/plutus 然后转发到http://localhost:10080 路径

举个简单例子:

我这里访问网关的url为

localhost:8080/plutus/finance/v1/bill/exception

那么实际的访问url就会被转发到

http://localhost:10080/plutus/finance/v1/bill/exception

4. 添加请求log Filter

@Slf4j
@Component
@AllArgsConstructor
public class RequestLogFilter implements GlobalFilterOrdered {

    private static final String START_TIME = "startTime";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestUrl = exchange.getRequest().getURI().getRawPath();
        // 构建成一条长 日志,避免并发下日志错乱
        StringBuilder beforeReqLog = new StringBuilder(300);
        // 日志参数
        List<Object> beforeReqArgs = new ArrayList<>();
        beforeReqLog.append("nn================ Cider Gateway Request Start  ================n");
        // 打印路由
        beforeReqLog.append("===> {}: {}n");
        // 参数
        String requestMethod = exchange.getRequest().getMethodValue();
        beforeReqArgs.add(requestMethod);
        beforeReqArgs.add(requestUrl);

        // 打印请求头
        HttpHeaders headers = exchange.getRequest().getHeaders();
        headers.forEach((headerName, headerValue) -> {
            beforeReqLog.append("===Headers===  {}: {}n");
            beforeReqArgs.add(headerName);
            beforeReqArgs.add(StringUtils.collectionToCommaDelimitedString(headerValue));
        });
        beforeReqLog.append("================ Cider Gateway Request End =================n");
        // 打印执行时间
        log.info(beforeReqLog.toString(), beforeReqArgs.toArray());

        exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            ServerHttpResponse response = exchange.getResponse();
            Long startTime = exchange.getAttribute(START_TIME);
            long executeTime = 0L;
            if (startTime != null) {
                executeTime = (System.currentTimeMillis() - startTime);
            }

            // 构建成一条长 日志,避免并发下日志错乱
            StringBuilder responseLog = new StringBuilder(300);
            // 日志参数
            List<Object> responseArgs = new ArrayList<>();
            responseLog.append("nn================ Cider Gateway Response Start  ================n");
            // 打印路由 200 get: /mate*/xxx/xxx
            responseLog.append("<=== {} {}: {}: {}n");
            // 参数
            responseArgs.add(response.getStatusCode().value());
            responseArgs.add(requestMethod);
            responseArgs.add(requestUrl);
            responseArgs.add(executeTime + "ms");

            // 打印请求头
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.forEach((headerName, headerValue) -> {
                responseLog.append("===Headers===  {}: {}n");
                responseArgs.add(headerName);
                responseArgs.add(StringUtils.collectionToCommaDelimitedString(headerValue));
            });

            responseLog.append("================  Cider Gateway Response End  =================n");
            // 打印执行时间
            log.info(responseLog.toString(), responseArgs.toArray());
        }));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

5. 搭建测试服务

这里我们搭建一个简单的plutus 服务,一个简单的SpringBoot 项目

配置文件

server:
  port: 10080
  servlet:
    context-path: /plutus

然后在写一个简单的接口

@RestController
@RequestMapping("/finance/v1")
@Slf4j
public class FinanceController {
  
   @GetMapping("/bill/exception")
    public String getFinanceExceptionVO() {
        System.out.println("路由转发成功");
        return "SUCCESS";
    }
  
}

测试

我们访问

localhost:8080/plutus/finance/v1/bill/exception
最新版本SpringCloud Gateway网关入门(一)
image-20211208195326814

我们在plutus 项目的控制台可以看到输出路由转发成功,代表请求转发成功了

最新版本SpringCloud Gateway网关入门(一)
image-20211208195651104

同时我们也能看到网关打印出了请求log

最新版本SpringCloud Gateway网关入门(一)
image-20211208195843686


原文始发于微信公众号(小奏技术):最新版本SpringCloud Gateway网关入门(一)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/30188.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!