GateWay service GateWay

Keywords: Java Spring Cloud Microservices gateway

spring Cloud gateway has the following features:

Dynamic routing: it can match any request attribute;

You can specify Predicate assertions and filters for routes

Integrate spring cloud service discovery

Easy to write Predicate assertions and filters

Request current limiting function

Support path rewriting

Three core concepts

route:

Routing is the basic module for building a gateway. It consists of id, target uri, a series of assertions and filters. If the assertion is true, the route will be matched

Assertion:

The developer can match all the contents of the http request (such as the request header and request parameters), and route the request if it matches the assertion

Filtering:

It refers to the instance of gatewayfilter in the spring framework. Using the filter, you can modify the request before or after it is routed

Namely

The web request locates the real service node by matching some conditions. And some fine control is carried out before and after the forwarding process.

Assertion is our matching condition, and filter can be understood as an omnipotent interceptor. With these two elements and the uri of the target, we can realize the specific routing

gateway configuration

The basic steps are as follows

  1. Create a SpringBoot project gateway and introduce gateway dependencies
  2. Write startup class
  3. Write basic configuration and routing rules
  4. Start the gateway service for testing

Import dependency:

<!--gateway-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos Service discovery dependency-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

Write startup class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {

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

Basic configuration and routing rules

Create the application.yml file as follows:

server:
  port: 10010 # Gateway port
spring:
  application:
    name: gateway # Service name
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos address
    gateway:
      routes: # Gateway routing configuration
        - id: user-service # Routing id, user-defined, as long as it is unique
          # uri: http://127.0.0.1: the destination address of 8081 # route http is the fixed address
          uri: lb://The target address lb of userservice # route is load balancing, followed by the service name
          predicates: # Routing assertion is to judge whether the request meets the conditions of routing rules
            - Path=/user/** # This is matched according to the path. It meets the requirements as long as it starts with / user /

We proxy all requests that meet the Path rule to the address specified by the uri parameter.

In this example, we proxy the request starting with / user / * * to lb://userservice. lb is load balancing. Pull the service list according to the service name to achieve load balancing. State routing

By default, the gateway will create a dynamic route with the microservices on the registry as the path for forwarding according to the service list registered in the registry, so as to realize the function of dynamic routing

Flow chart of Gateway Routing

Summary:

Gateway building steps:

  1. Create a project to introduce nacos service discovery and gateway dependency

  2. Configure application.yml, including basic service information, nacos address and routing

Routing configuration includes:

  1. Route id: the unique identifier of the route, which is similar to the primary key of the database and can be globally unique

  2. Routing destination (uri): the destination address of the route. http represents the fixed address and lb represents load balancing according to the service name (dynamic routing)

  3. Route assertions: Rules for judging routes,

  4. Routing filters: process requests or responses

Assertion factory

The assertion rules we write in the configuration file are just strings. These strings will be read and processed by the predict factory and transformed into conditions for routing judgment

For example, Path=/user / * * matches according to the path. This rule is determined by

org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory class

There are more than a dozen assertion factories like this in the spring cloud gateway:

nameexplainExample
AfterIs a request after a certain point in time- After=2037-01-20T17:42:47.789-07:00[America/Denver]
BeforeIs a request before a certain point in time- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
BetweenIs a request before two points in time- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
CookieThe request must contain some cookie s- Cookie=chocolate, ch.p
HeaderThe request must contain some header s- Header=X-Request-Id, \d+
HostThe request must be to access a host (domain name)- Host=.somehost.org,.anotherhost.org
MethodThe request mode must be the specified mode- Method=GET,POST
PathThe request path must conform to the specified rules- Path=/red/{segment},/blue/**
QueryThe request parameter must contain the specified parameter-Query=name, Jack or - Query=name
RemoteAddrThe ip address of the requester must be in the specified range- RemoteAddr=192.168.1.1/24
WeightWeight processing

Filter factory

Gateway filter is a filter provided in the gateway, which can process the requests entering the gateway and the responses returned by the microservice:

Types of routing filters

Spring provides 31 different routing filter factories. For example:

nameexplain
AddRequestHeaderAdd a request header to the current request
RemoveRequestHeaderRemove a request header from the request
AddResponseHeaderAdd a response header to the response result
RemoveResponseHeaderThere is a response header removed from the response result
RequestRateLimiterLimit requested traffic

Request header filter

Let's take AddRequestHeader as an example.

Requirement: add a request header to all requests entering userservice: truth = feifeifeiyyds

You only need to modify the application.yml file of the gateway service and add routing filtering:

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
        - id: orderservice    #The unique id of the route, the id of the route, has no fixed rules but requires uniqueness. It is recommended to match the service name
          uri: lb://userservice # satisfies the path to jump for this route and provides the route address of the service
          predicates:       #The assertion determines whether this route is satisfied
            - Path=/order/**
          filters:
            - AddRequestHeader=Truth,feifeiyyds # Add request header
    nacos:
      discovery:   #nacos service discovery
        server-addr: localhost:8848

The current filter is written under the userservice route, so it is only valid for requests to access the userservice.

Default filter

If you want to be effective for all routes, you can write the filter factory to default. The format is as follows:

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
      default-filters: # Default filter
      - AddRequestHeader=Truth, Itcast is freaking awesome! 

summary

What is the function of the filter?

① Process the routed request or response, such as adding a request header

② The filter configured under the route is only effective for the requests of the current route

What is the role of defaultFilters?

① Filters in effect for all routes

Global filter

In the previous section, the gateway provides 31 filters, but the function of each filter is fixed. If we want to intercept requests and do our own business logic, we can't do it.

Global filter action

The global filter is also used to handle all requests and microservice responses entering the gateway, just like the gateway filter. The difference is that the gateway filter is defined by configuration, and the processing logic is fixed; The logic of GlobalFilter needs to be implemented by writing code.

This is defined by implementing the GlobalFilter interface.

public interface GlobalFilter {
    /**
     *  Process the current request. If necessary, pass the request to the next filter through {@ link GatewayFilterChain}
     *
     * @param exchange Request context, which can obtain request, Response and other information
     * @param chain Used to delegate requests to the next filter 
     * @return {@code Mono<Void>} Return to indicate the end of the current filter business
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

Writing custom logic in filter can realize the following functions:

  • Login status judgment
  • Permission verification
  • Request current limit, etc

Custom global filter

Requirement: define a global filter, intercept the request, and judge whether the requested parameters meet the following conditions:

  • Whether there is authorization in the parameter,

  • Whether the authorization parameter value is admin

If both are met, release, otherwise intercept

realization:

Define a filter in the gateway:

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. Get request parameters
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2. Get the authorization parameter
        String auth = params.getFirst("authorization");
        // 3. Calibration
        if ("admin".equals(auth)) {
            // Release
            return chain.filter(exchange);
        }
        // 4. Interception
        // 4.1. Prohibit access and set the status code
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2. End processing
        return exchange.getResponse().setComplete();
    }
}

You can also register filters in this way

package com.cxf.globalFilter;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.MultiValueMap;


@Configuration
@Slf4j
public class myfilter {
    @Value("${server.port}")
    String port;
    @Bean
    @Order(-1)
    /**
     * Simply judge whether you have login permission
     */
    public GlobalFilter globalFilter1(){
        return (exchange, chain) -> {
            MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
            log.warn("The currently accessed port number is{}",port);
            String name = queryParams.getFirst("name");
            if("feifei".equals(name))  return chain.filter(exchange);
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        };
    }
}

Filter execution sequence

The request to enter the gateway will encounter three types of filters: the filter of the current route, DefaultFilter and GlobalFilter

After requesting a route, the current route filter, DefaultFilter and GlobalFilter will be merged into a filter chain (Collection), and each filter will be executed in turn after sorting:

What are the sorting rules?

  • Each filter must specify an order value of type int. the smaller the order value, the higher the priority and the higher the execution order.
  • GlobalFilter specifies the order value by implementing the Ordered interface or adding the @ order annotation, which is specified by ourselves
  • The order of routing filter and defaultFilter is specified by Spring. By default, it is incremented from 1 in the order of declaration.
  • When the order value of the filter is the same, it will be executed in the order of defaultfilter > routing filter > globalfilter.

For details, you can view the source code:

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters() method is to load defaultFilters first, then load filters of a route, and then merge.

The org.springframework.cloud.gateway.handler.FilteringWebHandler#handle() method will load the global filter, merge it with the previous filter, sort it according to the order, and organize the filter chain

Cross domain problem

Solve cross domain problems

In the application.yml file of gateway service, add the following configuration:

spring:
  cloud:
    gateway:
      # . . . 
      globalcors: # Global cross domain processing
        add-to-simple-url-handler-mapping: true # Solve the problem that the options request is intercepted
        corsConfigurations:
          '[/**]':
            allowedOrigins: # Which websites are allowed to make cross domain requests 
              - "http://localhost:8090"
            allowedMethods: # Allowed cross domain ajax request mode
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # Header information allowed to be carried in the request
            allowCredentials: true # Allow cookie s
            maxAge: 360000 # Validity of this cross domain detection

Posted by Froolah on Fri, 29 Oct 2021 08:29:16 -0700