【Spring Cloud】 Gateway网关 之 那些好玩的网关过滤器

举报
秋日的晚霞 发表于 2022/05/10 22:12:49 2022/05/10
【摘要】 1.添加请求头的网关过滤 AddRequestHeader匹配到的路由将添加指定的请求头和值 格式为 请求头名称 , 请求头值server: port: 81spring: cloud: gateway: routes: # 配置路由,是一个集合 - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名 ...

1.添加请求头的网关过滤 AddRequestHeader

匹配到的路由将添加指定的请求头和值 格式为 请求头名称 , 请求头值

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:80  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - AddRequestHeader=gateway,8848

改下controller代码

package gateway.controller;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import reactor.netty.http.server.HttpServerRequest;

import java.util.Iterator;
import java.util.Map;

/**
 * @author sz
 * @DATE 2022/3/20  20:15
 */

@Data
@RestController
public class HelloController {

    @Value("${server.port}")
    public String serverPort;

    @GetMapping("/say")
    public String say(
        @RequestHeader(name = "gateway",required = false)String value
    )
    {



        return "HelloWord   "+serverPort +"   "+value;
    }

    @GetMapping("/say/one")
    public String sayOne()
    {
        return "HelloWord one";
    }

}

返回结果

image-20220321205828575

发送请求时我们并没有携带请求头, 这是因为匹配到 apptest1路由后将指定的请求头添加到了请求中

2.添加请求参数的网关过滤 AddRequestParameter

匹配到的路由将添加指定的请求参数和值 格式为 请求参数名 , 请求参数值

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - AddRequestParameter=gateway,8848
package gateway.controller;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import reactor.netty.http.server.HttpServerRequest;

import java.util.Iterator;
import java.util.Map;

/**
 * @author sz
 * @DATE 2022/3/20  20:15
 */

@Data
@RestController
public class HelloController {

    @Value("${server.port}")
    public String serverPort;

    @GetMapping("/say")
    public String say(
        @RequestParam(name = "gateway",required = false)String value
    )
    {
        return "HelloWord   "+serverPort +"   "+value;
    }

    @GetMapping("/say/one")
    public String sayOne()
    {
        return "HelloWord one";
    }

}

image-20220321210415276

3.添加响应头的网关过滤 AddResponseHeader

匹配到的路由将添加指定的响应头参数和值 格式为 响应头名 , 响应头值

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - AddResponseHeader=gateway, 8848

image-20220321220449374

我们发送请求的时候并未携带任何请求头,但是response响应的时候可以看到添加了 我们指定的请求头

4.请求头映射网关过滤 MapRequestHeader

MapRequestHeader= 请求头一,请求头二

如果请求对象中请求头一不存在,不会对请求对象的请求头做出任何改变

如果请求对象中请求头一存在,请求头二不存在,将在请求对象的请求头中添加请求头二,且将请求头一的值赋值给请求头二

如果请求对象中请求头二已经存在也将不会对请求对象做出任何改变

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - MapRequestHeader=fuck, hello

这个什么意思呢?

如果请求对象的请求头中携带了fuck请求头,且没有hello请求头

将添加hello请求头,且将fuck请求头的值赋值给hello请求头

如果请求对象的请求头中已经携带了hello 请求头,或者没有fuck请求头,hello请求头将不会做出任何改变

来看演示

@Data
@RestController
public class HelloController {

    @Value("${server.port}")
    public String serverPort;

    @GetMapping("/say")
    public String say(
    )
    {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();

        String fuck = request.getHeader("fuck");
        System.out.println("fuck = " + fuck);
        String hello = request.getHeader("hello");
        System.out.println("hello = " + hello);

        return "HelloWord   ";
    }

    @GetMapping("/say/one")
    public String sayOne()
    {
        return "HelloWord one";
    }

}

Postman_BabRHpaYyi

5.添加路径前缀网关过滤器 PrefixPath

如果匹配当前路由,则在路径前添加指定前缀

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - PrefixPath=/prefix

如上配置

此时访问 /say是找不到请求映射的,因为请求对象的映射地址已经被添加前缀地址 /prefix

image-20220321222743896

此时访问的路径为 localhost:81/prefix/say

6.重定向网关过滤器 RedirectTo

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RedirectTo=302,http://localhost:8081/say/one

如果当前请求匹配此路由,将重定向到指定地址

image-20220321223154148

image-20220321223200384

7.删除请求头网关过滤器 RemoveRequestHeader

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RemoveRequestHeader=fuck

如果当前请求匹配此路由将删除请求头中指定的请求头参数

image-20220321223520891

请求对象中有请求头fuck,且值为you

但controller层接收的时候,已经没有了

image-20220321223628794

8.删除响应头网关过滤器 RemoveResponseHeader

如果当前请求匹配此路由,将删除响应头中指定的头信息

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RemoveResponseHeader=fuck

先不加此网关过滤器,访问 /say

 @GetMapping("/say")
    public String say(
    )
    {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();


        response.setHeader("fuck","you");

        return "HelloWord   ";
    }

image-20220321223952223

响应头中有fuck,且有值

如果我们加上此过滤器,重启网关模块再次访问

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RemoveResponseHeader=fuck

image-20220321224059097

响应头中的fuck已经被删除了

9.删除请求参数网关过滤器 PrefixPath

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RemoveRequestParameter=fuck

如果当前请求匹配此路由,请求参数中的fuck就被删除,如果有的情况下

10.路径重写网关过滤器 RewritePath

server:
  port: 81
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8081  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - RewritePath=/say(?<segment>/?.*), $\{segment}

如果当前请求匹配此路由,将按照指定规则重写路径

如上的配置 我们访问 /say/fuck 将会被重写为 访问 /fuck

 @GetMapping("/say")
    public String say(
    )
    {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();


        response.setHeader("fuck","you");

        return "HelloWord   ";
    }


    @GetMapping("/fuck")
    public String fuck(){
        return "RewritePath fuck";
    }

image-20220321225128973

11.模板重设路径网关过滤器 SetPath

如果请求匹配当前路由,将使用模板重新设置路径

什么意思呢 看下面这个配置

spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:80  # 匹配后提供服务的路由地址
          predicates:
            - Path=/fuck/{segment}
          filters:
            - SetPath=/{segment}

如果我们访问 /fuck/say 路径将被重新设置为 /say

image-20220326225714495

例如,我们访问的是 localhost:81/fuck/say 但实际上我们访问的 localhost:81/say

image-20220326225752792

12.设置响应状态码网关过滤器 SetStatus

将响应的状态码修改为指定的值,注意,仅仅只是修改响应状态码状态码

spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:80  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say
          filters:
            - SetStatus=404

image-20220326230514360

13.重试网关过滤器 Retry

  • retries:应尝试的重试次数。
  • statuses:应重试的 HTTP 状态代码,使用 表示。org.springframework.http.HttpStatus
  • methods:应重试的 HTTP 方法,通过使用 表示。org.springframework.http.HttpMethod
  • series:要重试的一系列状态代码,使用 表示。org.springframework.http.HttpStatus.Series
  • exceptions:应重试的引发的异常的列表。
  • backoff:为重试配置的指数退避。重试是在回退间隔为 之后执行的,其中迭代是。如果配置了 ,则应用的最大回退限制为 。如果为 true,则使用 计算回退。firstBackoff * (factor ^ n)``n``maxBackoff``maxBackoff``basedOnPreviousValue``prevBackoff * factor
spring:
  cloud:
    gateway:
      routes:   # 配置路由,是一个集合
        - id: apptest1 # 路由的ID, 没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:80  # 匹配后提供服务的路由地址
          predicates:
            - Path=/say/**
          filters:
            - name: Retry
              args:
                retries: 30
                statuses: NOT_FOUND
                methods: GET,POST
                backoff:
                  firstBackoff: 1000ms
                  maxBackoff: 5000ms
                  factor: 2
                  basedOnPreviousValue: false

如上面的配置 则效果为

请求的路径如果匹配当前路由( id: apptest1 ) 且返回的响应状态码为 NOT_FOUND (404) 则会重试30次

第一次重试间隔为 1秒 之后每次最大间隔为 5秒

为了看到测试效果 这里添加了全局过滤器

@Component
public class GlobalFilterConf implements GlobalFilter {

    Long start = System.currentTimeMillis();
    long end = 0L;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("收到请求 : "+exchange.getRequest().getPath().toString());

        Long temp =  end = System.currentTimeMillis();


        System.out.println("间隔: "+ (end - start)/1000);

        start = temp;

        return chain.filter(exchange);
    }
}

访问一个不存在的映射地址

image-20220326232849940

idea64_PDn6FXTaei

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200