Spring Cloud Gateway of Service Gateway

Table of contents

1. Gateway Introduction

2. Introduction to Gateway

Gateway Quick Start

basic version

Enhanced Edition

abbreviated version

Three, Gateway core architecture

Implementation process

Four, assert 

Built-in route assertion factory

Custom Route Assertion Factory


1. Gateway Introduction

Everyone knows that in the microservice architecture, a system will be split into many microservices. So how to call so many microservices as a client? If there is no gateway, we can only record the address of each microservice on the client side, and then call them separately.

 

The more popular gateways in the industry include the following:

  • Ngnix+lua uses nginx's reverse proxy and load balancing to achieve load balancing and high availability for api servers. Lua is a scripting language that can be used to write some simple logic. nginx supports lua scripts

  • Kong is developed based on Nginx+Lua, has high performance and stability, and has multiple available plug-ins (current limiting, authentication, etc.) that can be used out of the box. Problem: Only supports Http protocol; secondary development, free expansion is difficult; management API is provided, and there is a lack of easier-to-use control and configuration methods.

  • Zuul Netflix 's open source gateway has rich functions and is developed using JAVA, which is easy for secondary development Problems: lack of control and cannot be dynamically configured; there are many dependent components; processing Http requests depends on the web container, and its performance is not as good as Nginx

  • The gateway service developed by Spring Cloud Gateway to replace Zuul will be introduced in detail below.

2. Introduction to Gateway

Spring Cloud Gateway is a gateway developed by Spring based on technologies such as 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. Its goal is to replace Netflix Zuul, which not only provides a unified routing method, but also provides the basic functions of the gateway based on the Filter chain, such as: security, monitoring and current limiting.

advantage:

  • Strong performance: 1.6 times that of the first-generation gateway Zuul

  • Powerful functions: built-in many practical functions, such as forwarding, monitoring, current limiting , etc.

  • Elegant design, easy to expand

shortcoming:

  • Its implementation relies on Netty and WebFlux, not the traditional Servlet programming model, and the learning cost is high

  • It cannot be deployed in Servlet containers such as Tomcat and Jetty, but can only be executed as a jar package

  • Requires Spring Boot 2.0 and above to support

Gateway Quick Start

Requirement: Access the api gateway through the browser, and then forward the request to the commodity microservice through the gateway (there are three versions shown below)

basic version

Step 1: Create a new module and import related dependencies

<?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">
    <parent>
        <artifactId>Spring-Cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>api-gateway</artifactId>

    <dependencies>
        <!--gateway 注意 此模式不能引入starter-web -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <!--nacos客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

    </dependencies>

</project>

Add annotation @EnableDiscoveryClient to the main class

package com.dengxuyan.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }

}

Step 3: Add configuration files

server:
    port: 7000
spring:
    application:
        name: api-gateway
    cloud:
      nacos:
        discovery:
          server-addr: 127.0.0.1:8848
      gateway:
        routes:
          - id: product_route
            uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
            predicates:
              - Path=/product-serv/**
            filters:
              - StripPrefix=1
                  - id: product_route
                  uri: lb://shop-order # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
                  predicates:
                    - Path=/order-serv/**
                  filters:
                    - StripPrefix=1

Test effect

Access address of commodity microservice without gateway: http://localhost:8080/product/get/1

Access address via gateway product microservice: http://localhost:7000/product-serv/product/get/1

 Step 4: Start the project and access the microservice through the gateway

 

 

 

Enhanced Edition

Now write the address of the forwarding path hard in the configuration file. We have analyzed the problems caused by the hard writing of the address before. Next, we get this address from the registration center.

 Change the yml file on the basis of the basic version

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: product_route
          uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/product-serv/**
          filters:
            - StripPrefix=1

Test effect: You can randomly access an instance in the commodity microservice

background printing

 

 

abbreviated version

It is also possible to change the yml file on the original basis

Remove the configuration about routing

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务

Start the project and access the microservice through the gateway

 

 At this time, I found that as long as I access according to the format of gateway address/microservice/interface, I can get a successful response.

Replenish:

Cross-domain request: At this time, it is found that as long as the access is made according to the format of gateway address/microservice/interface, a successful response can be obtained.

spring:
  cloud:
    gateway:
      # 跨域
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods: "*"

Notes:

allowedHeaders: header allowed fields

allowedOrigins: allowed origins

allowedMethods: allow request method

Three, Gateway core architecture

Route (Route) is one of the most basic components in gateway, which represents a specific routing information carrier. The following information is mainly defined:

  • id, route identifier, different from other Routes.

  • uri, the destination uri pointed to by the route, that is, the microservice to which the client request is finally forwarded.

  • order, used for sorting among multiple Routes, the smaller the value, the higher the sorting, and the higher the matching priority.

  • predicate, the function of the assertion is to make conditional judgments, and only when the assertion returns true, the routing will be actually executed.

  • filter, the filter is used to modify the request and response information.

Implementation process

 

 The execution process is roughly as follows:

  1. Gateway Client sends a request to Gateway Server

  2. The request will first be extracted by the HttpWebHandlerAdapter and assembled into a gateway context

  3. Then the context of the gateway is passed to DispatcherHandler, which is responsible for dispatching the request to RoutePredicateHandlerMapping

  4. RoutePredicateHandlerMapping is responsible for route lookup, and judges whether the route is available according to the route assertion

  5. If the assertion is successful, the filter chain is created by FilteringWebHandler and called

  6. The request will go through the PreFilter--microservice--PostFilter method once, and finally return the response

Four, assert 

Predicate (assertion, predicate) is used for conditional judgment, only when the assertion returns true, the routing will be executed. Assertion means: under what conditions can routing and forwarding be carried out

Built-in route assertion factory

Spring Cloud Gateway includes a number of built-in assertion factories, all of which match against different attributes of HTTP requests.

 You can go to the official website to view related documents: Spring | Home

 

About the configuration file of the built-in route assertion project

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务
      routes:
        - id: product_route
          uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:  #添加了触发路由的条件
            - Path=/product-serv/**
            - Query=name,zk.
            - Method=POST #限制请求方式为POST
          filters:
            - StripPrefix=1

It is necessary to meet the three conditions of the assertion at the same time so that no error will be reported

The parameter values ​​and parameter names in the figure should correspond to those in the yml configuration file

Custom Route Assertion Factory

Let's set up a scenario: Suppose our application only allows people whose age is between (min, max) to visit.

Step 1: In the configuration file, add an Age assertion configuration

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务
      routes:
        - id: product_route
          uri: lb://shop-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/product-serv/**
            - Age=18,60
          filters:
            - StripPrefix=1

Step 2: Customize an assertion factory and implement the assertion method

package com.dengxuyan.apigateway.predicates;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

//这是一个自定义的路由断言工厂类,要求有两个
//1 名字必须是 配置+RoutePredicateFactory
//2 必须继承AbstractRoutePredicateFactory<配置类>
@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
    public AgeRoutePredicateFactory() {
        super(AgeRoutePredicateFactory.Config.class);
    }

    //用于从配置文件中获取参数值赋值到配置类中的属性上
    @Override
    public List<String> shortcutFieldOrder() {
         //这里的顺序要跟配置文件中的参数顺序一致
        return Arrays.asList("minAge", "maxAge");
    }

    //断言
    @Override
    public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config
                                                      config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //从serverWebExchange获取传入的参数
                String ageStr =
                        serverWebExchange.getRequest().getQueryParams().getFirst("age");
                if (StringUtils.isNotEmpty(ageStr)) {
                    int age = Integer.parseInt(ageStr);
                    return age > config.getMinAge() && age < config.getMaxAge();
                }
                else{
                    return  false;
                }
//                return true;
            }
        };
    }
    //配置类,用于接收配置文件中的对应参数
    @Data
    @NoArgsConstructor
    public static class Config {
        private int minAge;//18
        private int maxAge;//60
    }
}

Test results:

#The test found that when age is at (20,60), it can be accessed, and other ranges cannot access
http://localhost:7000/product-serv/product/1?age=40
http://localhost:7000/product-serv/product /1?age=10

 

 

 

 

Guess you like

Origin blog.csdn.net/weixin_66202611/article/details/128103854