Getting started with the latest version of SpringCloud Gateway

Posted by CostaKapo on Thu, 09 Dec 2021 08:11:27 +0100

background

Last time How to select online Spring Boot, Spring Cloud and Spring Cloud Alibaba versions as well as Zuul and Gateway request IO model comparison (WebFlux advantages) and Reactor model analysis

Select the Gateway in the micro service to use the Gateway. Next, let's build a simple Gateway to use

Introduction to spring cloud gateway

GitHub address: https://github.com/spring-cloud/spring-cloud-gateway

Official website document address: https://spring.io/projects/spring-cloud-gateway#learn

Spring Cloud gateway is a new project of Spring Cloud. The project is a gateway developed based on Spring 5.0, Spring Boot 2.0 and Project Reactor. It aims to provide a simple and effective unified API routing management method for microservice architecture.

As a gateway in the Spring Cloud ecosystem, the goal of Spring Cloud gateway is to replace Zuul. In Spring Cloud versions above 2.0, the latest performance versions above Zuul 2.0 are not integrated, and the old version of non Reactor mode before Zuul 2.0 is still used. In order to improve the performance of the gateway, the Spring Cloud gateway is implemented based on the WebFlux framework, and the underlying WebFlux framework uses the high-performance Reactor mode communication framework Netty.

Why do you need a gateway to speak? Let's think about what we need to do with multiple services without a gateway?

First, the relationship between our client traffic entry calls may be like this

What are the problems?

  1. If the authentication function is added, each service needs to be modified
  2. Cross domain issues require the transformation of each service
  3. Cross domain issues require the transformation of each service
  4. Gray publishing and dynamic routing need to transform each service
  5. There is a security problem. The Endpoint exposed by each microservice is fixed, and the client access needs to know the real Endpoint of each microservice

If we add a layer of gateway before the service as the storage of all traffic, the whole architecture will become as follows

Then all the above problems can be implemented uniformly in the gateway, and each service does not need to be implemented

Gateway getting started

1. Create a SpringBoot project

2. Add dependency

<?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. Configure routing forwarding

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

Here, the startup port of the gateway is simply configured as 8080, and then a routing rule is configured

The routing rule configured here is to intercept all requests. The path prefix is / plutus, and then forward them to http://localhost:10080 route

A simple example:

The url of the gateway I access here is

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

Then the actual access url will be forwarded to

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

4. Add request log Filter

@Slf4j
@Component
@AllArgsConstructor
public class RequestLogFilter implements GlobalFilter, Ordered {

    private static final String START_TIME = "startTime";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestUrl = exchange.getRequest().getURI().getRawPath();
        // Build a long log to avoid and distribute the log disorder
        StringBuilder beforeReqLog = new StringBuilder(300);
        // Log parameters
        List<Object> beforeReqArgs = new ArrayList<>();
        beforeReqLog.append("\n\n================ Cider Gateway Request Start  ================\n");
        // Print route
        beforeReqLog.append("===> {}: {}\n");
        // parameter
        String requestMethod = exchange.getRequest().getMethodValue();
        beforeReqArgs.add(requestMethod);
        beforeReqArgs.add(requestUrl);

        // Print request header
        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");
        // Print execution time
        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);
            }

            // Build a long log to avoid and distribute the log disorder
            StringBuilder responseLog = new StringBuilder(300);
            // Log parameters
            List<Object> responseArgs = new ArrayList<>();
            responseLog.append("\n\n================ Cider Gateway Response Start  ================\n");
            // Print route 200 get: /mate*/xxx/xxx
            responseLog.append("<=== {} {}: {}: {}\n");
            // parameter
            responseArgs.add(response.getStatusCode().value());
            responseArgs.add(requestMethod);
            responseArgs.add(requestUrl);
            responseArgs.add(executeTime + "ms");

            // Print request header
            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");
            // Print execution time
            log.info(responseLog.toString(), responseArgs.toArray());
        }));
    }

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

5. Build test service

Here we build a simple plutus service and a simple spring boot project

configuration file

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

Then write a simple interface

@RestController
@RequestMapping("/finance/v1")
@Slf4j
public class FinanceController {
  
  	@GetMapping("/bill/exception")
    public String getFinanceExceptionVO() {
        System.out.println("Route forwarding succeeded");
        return "SUCCESS";
    }
  
}

test

We visit

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

On the plutus project console, we can see that the output route is forwarded successfully, which means that the request is forwarded successfully

At the same time, we can also see that the gateway prints out the request log

About me

Pure technology dry goods blogger. It's not easy to be original. I think the article is good. Please scan the code and pay attention to me

Topics: Spring Boot Spring Cloud gateway