从springboot到springcloud第九篇----springcloud gateway

这一章开始接上zuul路由网关,接着写一下服务网gateway。

相比于zuul而言,gateway的功能更加强大,可以说zuul有的路由和过滤 gateway都有,还比zuul多一个断言功能。

所谓断言就是在http进行请求到路由的时候会将请求和路由进行匹配,匹配的过程就会用到断言,之后会决定走哪一个路由。

而匹配方式有很多种,会涉及到很多的路由工厂。

如:

After 路由断言工厂

Before路由断言工厂

Between路由断言工厂

Cookie路由断言工厂

Header路由断言工厂

Host路由断言工厂

Method路由断言工厂

Path路由断言工厂

Query路由断言工厂

RemoteAddr路由断言工厂 等。

 

进入到路由后还可以使用 pre 和 post 的两种方式进行过滤器的一系列操作。过滤器的工厂如下:

AddRequestHeader网关过滤工厂----添加请求头

AddRequestParameter网关过滤工厂----添加请求参数

AddResponseHeader网关过滤工厂----添加响应头

DedupeResponseHeader网关过滤工厂----剔除重复响应头

 CircuitBreaker网关过滤工厂----熔断(替代之前的hystrix)

FallbackHeaders网关过滤工厂----请求转发

MapRequestHeader 网关过滤工厂----扩充请求头

PrefixPath 网关过滤工厂----添加前缀

PreserveHostHeader 网关过滤工厂----保留原请求头

RequestRateLimiter 网关过滤工厂----请求限流

RedirectTo 网关过滤工厂----重定向

RemoveRequestHeader网关过滤工厂----删除请求头

RemoveResponseHeader 网关过滤工厂----删除响应头

RemoveRequestParameter 网关过滤工厂----删除请求参数

RewritePath 网关过滤工厂----重写路径

RewriteLocationResponseHeader 网关过滤工厂----重写响应头

RewriteResponseHeader 网关过滤工厂----以正则表达式的方式重写响应头的值

SaveSession 网关过滤工厂----保存session

SecureHeaders 网关过滤工厂----添加一系列的安全头

SetPath 网关过滤工厂----设置路径

SetRequestHeader 网关过滤工厂----替换请求头

SetResponseHeader 网关过滤工厂----替换响应头

SetStatus 网关过滤工厂----修改状态

StripPrefix 网关过滤工厂----阶段路径

Retry 网关过滤工厂----重试

RequestSize 网关过滤工厂----设置请求数据大小

ModifyRequestBody网关过滤工厂----修改请求体

ModifyResponseBody网关过滤工厂----修改响应体

default网关过滤工厂----默认的,可以应用于所有的路由

---------------------------------------------------------------

有点蒙?

首先来一个小Demo练练手,熟悉一下流程。就知道gateway是干嘛的了

 

一、小试牛刀

1.1、创建gateway-service服务

从springboot到springcloud第九篇----springcloud gateway_第1张图片

修改pom文件(添加)


            org.springframework.cloud
            spring-cloud-starter-contract-stub-runner
            
                
                    spring-boot-starter-web
                    org.springframework.boot
                
            
        

1.2、配置过滤器

package com.example.gatewayservice.config;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootConfiguration
@Component
public class GatewayConfig {

    @Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(p -> p
                        .path("/get")
                        .filters(f -> f.addRequestHeader("Hello", "World"))
                        .uri("http://httpbin.org:80"))
                .route(p -> p
                        .path("/delay/**")
//                        .host("www.hystrix.com")
                        .filters(f -> f.hystrix(config -> config
                                .setName("mycmd")
                                .setFallbackUri("forward:/fallback")))
                        .uri("http://httpbin.org:80"))
                .build();
    }
}

说明:

第一个route,里面是函数的匿名表达式,在header中添加"Hello":"World"和请求转发处理。

第二个route,增加了hystrix的熔断降级处理

 

1.3、添加熔断处理方法

package com.example.gatewayservice.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class GatewayController {

    @RequestMapping("/fallback")
    public Mono fallback() {
        return Mono.just("fallback");
    }

}

1.4、使用curl进行测试

1.4.1 测试请求转发

curl localhost:8080/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:52020\"",
    "Hello": "World",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.55.1",
    "X-Amzn-Trace-Id": "Root=1-5f198f9a-8bc3e804b36e6ae4f32721d2",
    "X-Forwarded-Host": "localhost:8080"
  },
  "origin": "0:0:0:0:0:0:0:1, 58.33.79.49",
  "url": "http://localhost:8080/get"
}

1.4.2 测试熔断降级

curl localhost:8080/delay/3
fallback

 

 

根据官网案例测试一下host

>curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3
curl -H 'host: www.hystrix.com' http://localhost:8080/delay/3
curl: (6) Could not resolve host: www.hystrix.com'
HTTP/1.1 404 Not Found
Content-Type: application/json
Content-Length: 136

{"timestamp":"2020-07-23T13:48:10.129+00:00","path":"/delay/3","status":404,"error":"Not Found","message":null,"requestId":"7c365d7e-7"}

什么鬼?我可是按照API来的,curl语法也没错吧!!!

经过一番爬坑发现,换成双引号就行了,有句mmp不知当讲不当讲

--------------------------------------------------------------------------------------

 

以上是练手部分,虽然可以在config bean 中进行配置,但是总觉得怪怪的。

之前也说了有那么多的断言工厂,接下来将以yml配置文件的形式一个个来。

1.注释或删除掉之前的相关配置,如config.java、application.properties

2.创建application.yml (如果习惯于用properties文件格式也没问题)

 

二、断言工厂

2.1、After路由断言工厂

修改application.yml文件

server:
  port: 8080

spring:
  application:
    name: gateway-service
  profiles:
    active: after_route

添加application-after_route.yml(配置文件的调用,后面不再做说明)

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: https://httpbin.org/
          predicates:
            - After=2017-01-20T17:42:47.789-07:00[America/Denver]

以上是  匹配路由为 2017年1月20日17:42时区(丹佛)之后的任何请求。然后将请求代理转发

测试:

curl localhost:8080/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:64374\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.55.1",
    "X-Amzn-Trace-Id": "Root=1-5f1ad7cc-0345d4655f39018e79072992",
    "X-Forwarded-Host": "localhost:8080"
  },
  "origin": "0:0:0:0:0:0:0:1, 58.33.125.63",
  "url": "https://localhost:8080/get"
}

Before路由断言工厂 和 Between路由断言工厂 见名知意 给出配置格式,不做测试

- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

 

2.2、Cookie路由断言工厂

有两种配置格式(以下工厂如有相同格式皆可)

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://httpbin.org/
        predicates:
        - Cookie=chocolate, ch.p
spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://httpbin.org/
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

将application.yml中的文件改为对cookie_route的调用,然后重启服务测试

curl -H "Cookie:mycookie=mycookievalue" localhost:8080/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Cookie": "mycookie=mycookievalue",
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:64908\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.55.1",
    "X-Amzn-Trace-Id": "Root=1-5f1adaf6-b5a5da1473da977e68166041",
    "X-Forwarded-Host": "localhost:8080"
  },
  "origin": "0:0:0:0:0:0:0:1, 58.33.102.47",
  "url": "https://localhost:8080/get"
}

2.3 Header路由断言工厂

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

以上是匹配header中有键为X-Request-Id, key为数字的请求

测试:

curl -H "X-Request-Id:111" localhost:8080/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:65454\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.55.1",
    "X-Amzn-Trace-Id": "Root=1-5f1ade28-7c4094785381b08095c0b464",
    "X-Forwarded-Host": "localhost:8080"
  },
  "origin": "0:0:0:0:0:0:0:1, 58.33.102.47",
  "url": "https://localhost:8080/get"
}

以下断言工厂的应用同理,这边给出配置,不再贴测试结果

 

2.4 Host路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: https://httpbin.org/
          predicates:
            - Host=**.somehost.org,**.anotherhost.org

2.5 Method路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: method_route
          uri: https://httpbin.org/
          predicates:
            - Method=GET,POST

2.6 Path路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: https://httpbin.org/
          predicates:
            - Path=/red/{segment},/blue/{segment}

2.7 Query路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: https://httpbin.org/
          predicates:
            - Query=green

2.8 RemoteAddr路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: remoteAddr_route
          uri: https://httpbin.org/
          predicates:
            - RemoteAddr=192.168.1.1/24

2.9 Weight路由断言工厂

spring:
  cloud:
    gateway:
      routes:
        - id: weight_route
          uri: https://httpbin.org/
          predicates:
            - Weight=192.168.1.1/24

 

三、过滤器

根据作用返回可以分为网关过滤器和全局过滤器

网关过滤器:只作用在所配置的路由上(或者配置作用全局,作用于全局)

全局过滤器:不需要配置,作用在所有的路由上

 

网关过滤器

3.1 AddRequestHeader网关过滤工厂----添加请求头

以 AddRequestHeader 为例 下面太多,贴出对应配置不进行一一演示

3.1.1 创建 application-add_request_header_route.yml,添加相关配置

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: https://httpbin.org/
          predicates:
            - After=2017-01-20T17:42:47.789-07:00[America/Denver]
          filters:
            - AddRequestHeader=X-Request-red, blue

3.1.2 应用该配置文件后重启测试

curl localhost:8080/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:50005\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.55.1",
    "X-Amzn-Trace-Id": "Root=1-5f1aed6d-98de345042a71ef80a3b4eb8",
    "X-Forwarded-Host": "localhost:8080",
    "X-Request-Red": "blue"
  },
  "origin": "0:0:0:0:0:0:0:1, 58.33.125.63",
  "url": "https://localhost:8080/get"
}

返回json的请求头中已添加 "X-Request-Red": "blue"

 

3.2 AddRequestParameter网关过滤工厂----添加请求参数

3.2.1添加固定请求参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://httpbin.org/
        filters:
        - AddRequestParameter=red, blue

3.2.1添加变量请求参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://httpbin.org/
        predicates:
        - Host: {segment}.myhost.org
        filters:
        - AddRequestParameter=foo, bar-{segment}

两种方式,下同,贴其一。

 

3.3 AddResponseHeader网关过滤工厂----添加响应头

filters:
        - AddResponseHeader=X-Response-Red, Blue

3.4 DedupeResponseHeader网关过滤工厂----剔除重复响应头

filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

3.5 CircuitBreaker网关过滤工厂----熔断(替代之前的hystrix)+ 3.6 FallbackHeaders网关过滤工厂----请求转发

filters:
        - name: CircuitBreaker
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback
        filters:
        - name: FallbackHeaders
          args:
            executionExceptionTypeHeaderName: Test-Header

3.7 MapRequestHeader 网关过滤工厂----扩充请求头

filters:
        - MapRequestHeader=Blue, X-Request-Red

3.8 PrefixPath 网关过滤工厂----添加前缀

filters:
        - PrefixPath=/mypath

3.9 PreserveHostHeader 网关过滤工厂----检查请求头

filters:
        - PreserveHostHeader

检查是否存在该请求头

3.10 RequestRateLimiter 网关过滤工厂----请求限流

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20
            redis-rate-limiter.requestedTokens: 1

配合redis使用做请求限流

使用的算法是令牌桶算法。

redis-rate-limiter.replenishRate属性是您希望用户每秒允许多少个请求,而没有任何丢弃的请求。这是令牌桶被填充的速率。

redis-rate-limiter.burstCapacity属性是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。

redis-rate-limiter.requestedTokens属性是请求花费多少令牌。这是每个请求从存储桶中提取的令牌数,默认为1

 

3.11 RedirectTo 网关过滤工厂----重定向

filters:
        - RedirectTo=302, https://acme.org

3.12 RemoveRequestHeader网关过滤工厂----删除请求头

filters:
        - RemoveRequestHeader=X-Request-Foo

3.13 RemoveResponseHeader 网关过滤工厂----删除响应头

filters:
        - RemoveResponseHeader=X-Response-Foo

3.14 RemoveRequestParameter 网关过滤工厂----删除请求参数

filters:
        - RemoveRequestParameter=red

3.15 RewritePath 网关过滤工厂----重写路径

filters:
        - RewritePath=/red(?/?.*), $\{segment}

3.16 RewriteLocationResponseHeader 网关过滤工厂----重写响应头

filters:
        - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

3.17 RewriteResponseHeader 网关过滤工厂----以正则表达式的方式重写响应头的值

filters:
        - RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***

3.18 SaveSession 网关过滤工厂----保存session

filters:
        - SaveSession

3.19 SecureHeaders 网关过滤工厂----添加一系列的安全头

官方参考该博客建议,添加了一下请求头 https://blog.appcanary.com/2017/http-security-headers.html

  • X-Xss-Protection:1 (mode=block

  • Strict-Transport-Security (max-age=631138519

  • X-Frame-Options (DENY)

  • X-Content-Type-Options (nosniff)

  • Referrer-Policy (no-referrer)

  • Content-Security-Policy (default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline)'

  • X-Download-Options (noopen)

  • X-Permitted-Cross-Domain-Policies (none)

要更改默认值,请在spring.cloud.gateway.filter.secure-headers名称空间中设置适当的属性。可以使用以下属性:

  • xss-protection-header

  • strict-transport-security

  • x-frame-options

  • x-content-type-options

  • referrer-policy

  • content-security-policy

  • x-download-options

  • x-permitted-cross-domain-policies

要禁用默认值,请spring.cloud.gateway.filter.secure-headers.disable用逗号分隔的值设置属性。以下示例显示了如何执行此操作:

spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security

3.20 SetPath 网关过滤工厂----设置路径

        predicates:
        - Path=/red/{segment}
        filters:
        - SetPath=/{segment}

3.21 SetRequestHeader 网关过滤工厂----替换请求头

filters:
        - SetRequestHeader=X-Request-Red, Blue

3.22 SetResponseHeader 网关过滤工厂----替换响应头

filters:
        - SetResponseHeader=X-Response-Red, Blue

3.23 SetStatus 网关过滤工厂----修改状态

filters:
        - SetStatus=401

3.24 StripPrefix 网关过滤工厂----阶段路径

        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

3.25 Retry 网关过滤工厂----重试

Retry GatewayFilter工厂支持以下参数:

  • retries:应尝试的重试次数。

  • statuses:应重试的HTTP状态代码,使用表示org.springframework.http.HttpStatus

  • methods:应重试的HTTP方法,以表示org.springframework.http.HttpMethod

  • series:要重试的一系列状态代码,用表示org.springframework.http.HttpStatus.Series

  • exceptions:应重试的引发异常的列表。

  • backoff:为重试配置的指数补偿。重试在的退避间隔后执行firstBackoff * (factor ^ n),其中n为迭代。如果maxBackoff已配置,则应用的最大退避限制为maxBackoff。如果basedOnPreviousValue为true,则使用计算退避prevBackoff * factor

Retry如果启用了以下默认过滤器配置:

  • retries:3次

  • series:5XX系列

  • methods:GET方法

  • exceptionsIOExceptionTimeoutException

  • backoff:禁用

以下清单配置了Retry GatewayFilter

spring:
  cloud:
    gateway:
      routes:
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

 

3.26 RequestSize 网关过滤工厂----设置请求数据大小

filters:
        - name: RequestSize
          args:
            maxSize: 5000000

3.27 ModifyRequestBody网关过滤工厂----修改请求体

该过滤器只能使用java代码的方式进行配置

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
                    (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
        .build();
}

static class Hello {
    String message;

    public Hello() { }

    public Hello(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

3.28 ModifyResponseBody网关过滤工厂----修改响应体

该过滤器只能使用java代码的方式进行配置

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyResponseBody(String.class, String.class,
                    (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
        .build();
}

3.29 default网关过滤工厂----默认的,可以应用于所有的路由

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

 

全局过滤器

使用方式如下:

package com.example.gatewayservice.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class TokenFilter implements GlobalFilter, Ordered {
    
    Logger logger = LoggerFactory.getLogger(TokenFilter.class);
    
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if(token == null || token.isEmpty()){
            logger.warn("token is empty...");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}
@Bean
    public TokenFilter tokenFilter(){
        return new TokenFilter();
    }

重启测试:

curl localhost:8080/get
2020-07-24 23:03:14.139  WARN 11940 --- [ctor-http-nio-2] c.e.gatewayservice.filter.TokenFilter    : token is empty...

 

 

源码地址:https://github.com/houfanGitHub/springcloud.git

你可能感兴趣的:(springcloud,java)