【SpringCloud】04 网关springcloud gateway

gateway springcloud gateway

The above architecture will have many problems:

  1. The client requests different microservices multiple times, increasing the complexity of client code or configuration writing.

  2. Authentication is complicated and each service requires independent authentication.

  3. There are cross-domain requests, which are relatively complex to handle in certain scenarios.

Insert image description here

What can a gateway do?

  1. Route forwarding.
  2. Authentication.
  3. Unified cross-domain solution.
  4. black and white list ip
  5. Sensitive words
  6. Limiting

1. Commonly used gateways

  1. nginx: it can be used as a gateway

  2. zuul: Early microservices used this component as a gateway, but its bottom layer used servlets. Its efficiency is very slow. And it's a Netflix product. Netflix expected the product zuul2, but zuul2 died.

  3. springcloud gateway: It is a gateway produced by spring company. Its efficiency is 1.6 times that of zuul.

2. springcloud gateway

Spring Cloud Gateway is Spring company based onSpring 5.0,Spring Boot 2.0 和 Project ReactorA gateway developed by other technologies, which aims to provide a microservice architectureSimple and effective unified API routing management method. Its goal is to replace Netflix Zuul, which not only provides a unified routing method, but also provides basic gateway functions based on the Filter chain, such as: security, monitoring and flow limiting.

3. How to use

In fact, the gateway is also a microservice, so we can also create a gateway microservice.

Insert image description here

Introducing spring-cloud-starter-gateway

<dependencies>
    <!--这里引入了gateway的依赖后,不能引用spring-boot-starter-web依赖。
        因为:gateway它使用的是netty服务器。
        spring-boot-starter-web里面内置了tomcat服务器.
    -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

(2) Create the main startup class

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

(3) Modify configuration file

# 配置路由
spring:
  cloud:
    gateway:
      routes:
        - id: shop-product #路由的唯一标识。如果没有给定默认按照UUID生成
          uri: http://localhost:8001 #真实转发的地址
          predicates: # 断言 如果断言满足要求,则转发到uri指定的真实地址.
            - Path=/product/** # 如果客户的请求路径以product开头,则满足该断言要求,则转发的uri真实地址。

        - id: shop-order
          uri: http://localhost:9001
          predicates:
            - Path=/order/**

(4) Start gateway

(5)Demonstration
Insert image description here

4. gateway load balancing forwarding

Is there anything that needs to be improved in the above configuration file?

  • Our actual forwarding address is in case we build a cluster. We have observed that the gateway itself is also a microservice. Can we pull the relevant microservices from the registration center and then access the service?
    Insert image description here

(1)Introduce dependencies on nacos registration center

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

(2) Modify the configuration file
Insert image description here
test:
Insert image description here

5. Simple version

# 配置路由
spring:
  cloud:
    gateway:
      routes:
        - id: shop-product #路由的唯一标识。如果没有给定默认按照UUID生成
          uri: lb://shop-product #真实转发的地址 lb: ---loadbalanced
          predicates: # 断言 如果断言满足要求,则转发到uri指定的真实地址.
            - Path=/product/** # 如果客户的请求路径以product开头,则满足该断言要求,则转发的uri真实地址。

        - id: shop-order
          uri: lb://shop-order
          predicates:
            - Path=/order/**

Thinking: If you add a new microservice at this time, you need to modify the routing configuration of the gateway.

Change to automatic route discovery.

(1) Modify the gateway configuration file
Insert image description here
(2) Access the gateway
Insert image description here

6. gateway process

Insert image description here

6.1 Types of assertions

l Assertion factory based on Datetime type

This type of assertion makes judgments based on time. There are three main types:

AfterRoutePredicateFactory: Receives a date parameter and determines whether the requested date is later than the specified date

BeforeRoutePredicateFactory: Receives a date parameter to determine whether the requested date is earlier than the specified date

BetweenRoutePredicateFactory: Receives two date parameters and determines whether the requested date is within the specified time period

-After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]

l Assertion factory based on remote address

RemoteAddrRoutePredicateFactory : Receives an IP address segment and determines whether the requesting host address is in the address segment

-RemoteAddr=192.168.1.1/24

lCookie -based assertion factory

CookieRoutePredicateFactory: Receives two parameters, the cookie name and a regular expression. Judgment request

Whether the cookie has the given name and value matches the regular expression.

-Cookie=chocolate, ch.

l Header-based assertion factory

HeaderRoutePredicateFactory: Receives two parameters, header name and regular expression. Determine whether the request header is

Has the given name and value matches the regular expression. key value

-Header=X-Request-Id, \d+

l Host-based assertion factory

HostRoutePredicateFactory: Receives one parameter, host name pattern. Determine whether the requested Host meets the matching rules.

-Host=**.testhost.org

l Assertion factory based on Method request method

MethodRoutePredicateFactory: Receives a parameter to determine whether the request type matches the specified type.

-Method=GET

l Assertion factory based on Path request path

PathRoutePredicateFactory: Receives a parameter to determine whether the URI part of the request satisfies the path rules.

-Path=/foo/{segment}Assertion factory based on Query request parameters

QueryRoutePredicateFactory: Receives two parameters, request param and regular expression, and determines whether the request parameter has

Has the given name and the value matches the regular expression.

-Query=baz, ba.

l Assertion factory based on routing weight

WeightRoutePredicateFactory: receives a [group name, weight], and then forwards routes in the same group according to the weight

routes:

-id: weight_route1 uri: host1 predicates:

-Path=/product/**

-Weight=group3, 1

-id: weight_route2 uri: host2 predicates:

-Path=/product/**

-Weight= group3, 9

If the above built-in assertions cannot meet your needs, you can customize assertions. 【learn】

Case: Age must be between 18 and 65 to access the microservices I specified.

Custom assertion class

package com.aaa.predicate;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.BetweenRoutePredicateFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import javax.validation.constraints.NotNull;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-21 16:27
 **/
@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(Config config) {
    
    

        return (serverWebExchange)->{
    
    
            ServerHttpRequest request = serverWebExchange.getRequest();
            //获取传递的年龄
            String age = request.getHeaders().getFirst("age");
            if(StringUtils.hasText(age)){
    
    
                int a = Integer.parseInt(age);
                if(a>=config.getMinAge()&&a<=config.getMaxAge()){
    
    
                    return true;
                }
            }
            return false;
        };
    }

    @Validated
    public static class Config {
    
    
        @NotNull
        private int minAge;
        @NotNull
        private int maxAge;

        public int getMinAge() {
    
    
            return minAge;
        }

        public void setMinAge(int minAge) {
    
    
            this.minAge = minAge;
        }

        public int getMaxAge() {
    
    
            return maxAge;
        }

        public void setMaxAge(int maxAge) {
    
    
            this.maxAge = maxAge;
        }
    }
}

Insert image description here
Insert image description here

Summary:
Insert image description here
gateway: gateway, routing and forwarding

ribbon: achieve load balancing

openfeign: Complete calls between services.

nacos: registration center

6.2 Filters in gateway

You can add corresponding request settings before the request reaches the microservice, and add some settings for the response result after the response.

There are many kinds of filtering inside the gateway.
https://www.cnblogs.com/zhaoxiangjun/p/13042189.html

filter factory effect parameter
AddRequestHeader Add header to original request Header name and value
AddRequestParameter Add request parameters to original request Parameter name and value
AddResponseHeader Add header to original response Header name and value
DedupeResponseHeader Remove duplicate values ​​from response headers Header name and deduplication strategy that need to be removed
Hystrix Introduce Hystrix's circuit breaker protection HystrixCommand name for routing
FallbackHeaders Add specific exception information to the request header of fallbackUri Header name
PrefixPath Add prefix to original request path prefix path
PreserveHostHeader Add a preserveHostHeader=true attribute to the request. The routing filter will check this attribute to decide whether to send the original Host. none
RequestRateLimiter Used to limit request current, the current limiting algorithm is token bucket keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo Redirect the original request to the specified URL http status code and redirected url
RemoveHopByHopHeadersFilter Delete a series of headers specified by the IETF organization for the original request It is enabled by default. You can specify which headers to delete only through configuration.
RemoveRequestHeader Delete a header for the original request Header name
RemoveResponseHeader Remove a header from the original response Header name
RewritePath Rewrite the original request path Regular expression of the original path and the regular expression of the rewritten path
RewriteResponseHeader Rewrite a header in the original response Header name, regular expression of value, rewritten value
SaveSession Force a WebSession::save operation before forwarding the request none
secureHeaders Add a series of security headers to the original response None, supports modifying the values ​​of these security response headers
SetPath Modify the original request path modified path
SetResponseHeader Modify the value of a Header in the original response Header name, modified value
SetStatus Modify the status code of the original response HTTP status code, which can be a number or a string
StripPrefix Path used to truncate the original request Use a number to indicate the number of paths to truncate
Retry Retry with different responses retries、statuses、methods、series
RequestSize Set the maximum request packet size allowed to be received. If the request packet size exceeds the set value, 413 Payload Too Large will be returned. Request packet size, unit is bytes, default value is 5M
ModifyRequestBody Modify the original request body content before forwarding the request Modified request body content
ModifyResponseBody Modify the contents of the original response body Modified response body content
Default Add filter to all routes Filter factory name and value

Tips: Each filter factory corresponds to an implementation class, and the names of these classes must end with GatewayFilterFactory, which is a convention of Spring Cloud Gateway. For example, the implementation class corresponding to AddRequestHeader is AddRequestHeaderGatewayFilterFactory.

Example: StripPrefix is ​​used to truncate the path of the original request.
Insert image description here
Test:
Insert image description here
Example: Set response status code 2500
Insert image description here
Insert image description here

6.3 Custom global filters

Example: Authentication filtering.

The built-in filters can already complete most of the functions, but for some business functions developed by enterprises, we still need to write our own filters to implement them. Then we can customize a filter in the form of code to complete the unified process. Certification verification.

Authentication logic under development:

  • When the client requests the service for the first time, the server authenticates the user's information (login)

  • After the authentication is passed, the user information is encrypted to form token[jwt] and returned to the client as the login credential.

  • For each subsequent request, the client will carry the authentication token [carrying request header]

  • The server decrypts the token and determines whether it is valid.

Insert image description here

package com.aaa.filter;

import com.alibaba.fastjson.JSON;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: qy156-shop-parent
 * @description:
 * @author: 闫克起2
 * @create: 2022-11-22 15:07
 **/
@Component
public class LoginFilter implements GlobalFilter, Ordered {
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //判断请求路径是否为放行。
        String path = request.getPath().toString();
        if("/login".equals(path)){
    
    
            return chain.filter(exchange);//放行
        }
        //获取请求头的token值。
        String token = request.getHeaders().getFirst("token");
        if(StringUtils.hasText(token)){
    
    
             //校验token是否有效
             if("admin".equals(token)){
    
    
                 return chain.filter(exchange);//放行
             }
        }

        //3.1设置状态码
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //3.2封装返回数据
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "未登录");
        map.put("code", "NOTLOGING");

        //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数据
        return response.writeWith(Mono.just(buffer));
    }

    //优先级 值越小优先级越高
    @Override
    public int getOrder() {
    
    
        return 0;
    }
}

7. Unify cross-domain solutions

The first is through the configuration file

spring:
 cloud:
     gateway:
       globalcors:
         cors-configurations:
           '[/**]':
             allowedOrigins: "*"
             allowedHeaders: "*"
             allowedMethods: "*"
       default-filters:
        		- DedupeResponseHeader=Vary Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_FIRST

The second way is to write a configuration class

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {
    
    
    @Bean
    public CorsWebFilter corsFilter() {
    
    
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

Guess you like

Origin blog.csdn.net/qq_60969145/article/details/127986060