首页 > 其他分享 >Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)

时间:2022-11-09 19:08:31浏览次数:57  
标签:http String Spring Alibaba Cloud 过滤器 org message 路由


前两篇博客已经介绍了十一种路由过滤器工厂:

  • ​​Spring Cloud Alibaba:Gateway之路由过滤器工厂(一)​​
  • ​​Spring Cloud Alibaba:Gateway之路由过滤器工厂(二)​​

随着​​Gateway​​​的不断更新,​​Gateway​​提供的路由过滤器工厂种类一直在增加,目前已经有三十多种了(不同版本可能不一样)。

搭建工程

一个父​​module​​​和两个子​​module​​​(​​server module​​​提供服务,​​gateway module​​实现网关)。

父​​module​​​的​​pom.xml​​:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.kaven</groupId>
<artifactId>alibaba</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

<description>Spring Cloud Alibaba</description>
<modules>
<module>gateway</module>
<module>server</module>
</modules>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud-version>Hoxton.SR9</spring-cloud-version>
<spring-cloud-alibaba-version>2.2.6.RELEASE</spring-cloud-alibaba-version>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

server module

​pom.xml​​:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.kaven</groupId>
<artifactId>alibaba</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>server</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

​application.yml​​:

server:
port: 8085

接口定义:

package com.kaven.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MessageController {

@GetMapping("/message")
public String getMessage() {
return "hello kaven, this is spring cloud alibaba";
}
}

启动类:

package com.kaven.alibaba;

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

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

gateway module

​pom.xml​​:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.kaven</groupId>
<artifactId>alibaba</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>gateway</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
</project>

​application.yml​​:

server:
port: 8086

spring:
cloud:
gateway:
routes:
- id: server
uri: http://localhost:8085
predicates:
- Path=/message

启动类:

package com.kaven.alibaba;

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

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

StripPrefix

​StripPrefix​​​路由过滤器工厂接受一个参数(​​parts​​​),​​parts​​参数表示在将请求发送到下游服务之前要从请求中剥离的路径数量。

源码相关部分:

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_spring cloud


增加路由过滤器的配置(全写):

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

或(简写):

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

访问​​http://127.0.0.1:8086/1/2/message​​​,会被路由到​​http://127.0.0.1:8085/message​​。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_maven_02

Retry

​Retry​​路由过滤器工厂接受以下参数:

  • ​retries​​:应该尝试的重试次数。
  • ​series​​​:要重试的一系列状态码,用​​HttpStatus.Series​​表示。
  • ​statuses​​​:应该重试的​​HTTP​​状态码,用​​HttpStatus​​表示。
  • ​methods​​​:应该重试的​​HTTP​​方法,用​​HttpMethod​​表示。
  • ​exceptions​​:应该重试的抛出异常列表。
  • Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_gateway_03

  • ​backoff​​​:为重试配置的指数退避,在退避间隔​​firstBackoff * (factor ^ n)​​之后执行重试,其中​​n​​是重试次数减一(即​​n​​的取值范围为​​[0,retries-1]​​)。如果​​maxBackoff​​已配置,则应用的最大退避限制为​​maxBackoff​​。如果​​basedOnPreviousValue​​为真,则使用​​prevBackoff * factor​​计算退避(也不能超过​​maxBackoff​​)。
  • Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_04

修改路由过滤器的配置:

predicates:
- Path=/message
filters:
- name: Retry
args:
retries: 5
statuses: Internal_Server_Error
methods: GET,POST
backoff:
firstBackoff: 300ms
maxBackoff: 1300ms
factor: 2
basedOnPreviousValue: false

​Internal_Server_Error​​​对应​​500​​​状态码(详见​​HttpStatus​​类)。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_spring cloud_05

修改接口:

AtomicLong time = new AtomicLong(0);

@GetMapping("/message")
public String getMessage(HttpServletResponse response) {
if(time.get() != 0) {
System.out.println(System.currentTimeMillis() - time.get());
}
time.set(System.currentTimeMillis());
response.setStatus(500);
return "hello kaven, this is spring cloud alibaba";
}

访问​​http://127.0.0.1:8086/message​​​,在​​server module​​中会输出如下所示的重试间隔毫秒数(接近网关设置的重试间隔时间):

327
623
1216
1308
1307

是符合预期的。

​HTTP​​系列状态码的枚举类:

public enum Series {
INFORMATIONAL(1),
SUCCESSFUL(2),
REDIRECTION(3),
CLIENT_ERROR(4),
SERVER_ERROR(5);
...
}

如下所示的配置可以对​​5XX​​系列状态码的响应进行请求重试。

predicates:
- Path=/message
filters:
- name: Retry
args:
retries: 5
series: SERVER_ERROR # 默认值
backoff:
firstBackoff: 300ms
maxBackoff: 1300ms
factor: 2
basedOnPreviousValue: true

访问​​http://127.0.0.1:8086/message​​,结果是类似的。

修改路由过滤器的配置:

predicates:
- Path=/message
filters:
- name: Retry
args:
retries: 5
exceptions: java.util.concurrent.TimeoutException,java.lang.ClassNotFoundException
backoff:
firstBackoff: 300ms
maxBackoff: 1300ms
factor: 2
basedOnPreviousValue: true

修改接口:

AtomicLong time = new AtomicLong(0);

@GetMapping("/message")
public String getMessage(@RequestParam("isThrow") boolean isThrow) throws ClassNotFoundException {
if(time.get() != 0) {
System.out.println(System.currentTimeMillis() - time.get());
}
time.set(System.currentTimeMillis());
if(isThrow) throw new ClassNotFoundException();
return "hello kaven, this is spring cloud alibaba";
}

访问​​http://127.0.0.1:8086/message​​​,在​​server module​​中的输出如下图所示:

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_maven_06

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_gateway_07


也是符合预期的。

RequestSize

当请求大小大于允许的限制时,​​RequestSize​​​路由过滤器工厂可以限制请求到达下游服务。过滤器接受一个​​maxSize​​​参数,​​maxSize​​​是一个​​DataSize​​​类型,所以值可以被定义为一个数字,后跟一个可选的​​DataUnit​​​后缀,例如​​KB​​​或​​MB​​​,字节的默认值为​​B​​。它是以字节为单位定义的请求的允许大小限制。

BYTES("B", DataSize.ofBytes(1L)),
KILOBYTES("KB", DataSize.ofKilobytes(1L)),
MEGABYTES("MB", DataSize.ofMegabytes(1L)),
GIGABYTES("GB", DataSize.ofGigabytes(1L)),
TERABYTES("TB", DataSize.ofTerabytes(1L));

源码相关部分:

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_08


修改路由过滤器的配置:

predicates:
- Path=/message
filters:
- name: RequestSize
args:
maxSize: 5KB

请求负载限制为​​5KB​​。

修改接口:

@GetMapping("/message")
public String getMessage() {
return "hello kaven, this is spring cloud alibaba";
}

访问​​http://127.0.0.1:8086/message​​成功(请求负载没有超过限制)。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_spring_09


访问​​http://127.0.0.1:8086/message​​失败(请求负载超过限制)。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_10


​PAYLOAD_TOO_LARGE​​​和​​REQUEST_ENTITY_TOO_LARGE​​​(即将被抛弃)表示同一个状态码,而网关响应的是​​PAYLOAD_TOO_LARGE​​​(上面的源码截图),​​Postman​​​显示的是​​REQUEST_ENTITY_TOO_LARGE​​​,可能是博主的​​Postman​​版本的原因。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_maven_11


Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_gateway_12


响应头里面的错误信息显示请求负载限制是​​5.1KB​​​,很显然是换算不一致的问题(过滤器使用​​1000​​​,而​​DataSize​​​使用​​1024​​):

private static String getReadableByteCount(long bytes) {
int unit = 1000;
if (bytes < unit) {
return bytes + " B";
}
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = Character.toString(PREFIX.charAt(exp - 1));
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
private static final long BYTES_PER_KB = 1024L;
private static final long BYTES_PER_MB = 1048576L;
private static final long BYTES_PER_GB = 1073741824L;
private static final long BYTES_PER_TB = 1099511627776L;

SetRequestHostHeader

在某些情况下,可能需要覆盖请求的主机头。在这种情况下,​​SetRequestHostHeader​​​路由过滤器工厂可以用指定的值替换现有的主机头。过滤器接受一个​​host​​参数。

源码相关部分:

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_13


由源码可知,请求没有主机头时,也会给请求添加指定值的主机头。

修改路由过滤器的配置:

predicates:
- Path=/message
filters:
- name: SetRequestHostHeader
args:
host: kaven.top

修改接口:

@GetMapping("/message")
public String getMessage(HttpServletRequest httpServletRequest) {
StringBuilder result = new StringBuilder("hello kaven, this is spring cloud alibaba\n");
result.append(getKeyAndValue(httpServletRequest));
return result.toString();
}

// 获取header中key和value组成的StringBuilder
private StringBuilder getKeyAndValue(HttpServletRequest httpServletRequest) {
StringBuilder result = new StringBuilder();
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = headerNames.nextElement();
String value = httpServletRequest.getHeader(key);
result.append(key).append(" : ").append(value).append("\n");
}
return result;
}

访问​​http://127.0.0.1:8086/message​​,请求的主机头就会被修改成指定的值。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_14


请求没有主机头时,也会给请求添加指定值的主机头。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_maven_15


注释掉路由过滤器,请求的主机头是本地的套接字。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_gateway_16

ModifyRequestBody

使用​​ModifyRequestBody​​​过滤器在网关向下游服务发送请求​​Body​​​之前修改请求​​Body​​​。此过滤器目前只能通过使用​​Java DSL​​进行配置。

在​​gateway module​​​中添加一个​​bean​​:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
String uri = "http://127.0.0.1:8085";
return builder.routes()
.route("server", r -> r.path("/message")
.filters(f -> f.modifyRequestBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> Mono.just(s.toUpperCase())))
.uri(uri))
.build();
}

其实就是用代码的形式来定义路由的处理流程,因此,之前介绍过的路由过滤器都可以通过这种形式添加到路由中。​​server​​​是路由的​​id​​​,​​path​​​方法是给路由添加​​Path​​​断言,​​modifyRequestBody​​​方法是给路由添加​​ModifyRequestBody​​​路由过滤器,这些​​lambda​​​表达式应该容易看懂,​​modifyRequestBody​​​方法的第一个参数表示请求​​Body​​​输入时需要转换的类型,第二个参数表示请求​​Body​​​输出时需要转换的类型,而第三个参数就是请求发送到下游服务时的新​​Content-Type​​​ 请求头,最后一个参数就是用于修改请求​​Body​​​的方法(这里就是将字符串全部变成大写),​​uri​​方法是给路由指定路由匹配成功后的请求转发路径。

  • ​​Spring Cloud Alibaba:Gateway网关 & 路由断言工厂​​

修改接口:

@GetMapping("/message")
public String getMessage(@RequestBody String message) {
return message + "\nhello kaven, this is spring cloud alibaba\n";
}

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_java_17

ModifyResponseBody

使用​​ModifyResponseBody​​​过滤器在响应​​Body​​​发送回客户端之前对其进行修改。此过滤器目前也只能通过使用​​Java DSL​​进行配置。

在​​gateway module​​​中添加一个​​bean​​​(和之前那个​​bean​​类似):

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
String uri = "http://127.0.0.1:8085";
return builder.routes()
.route("server", r -> r.path("/message")
.filters(f -> f.modifyResponseBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> Mono.just(s.toUpperCase())))
.uri(uri))
.build();
}

通过​​modifyResponseBody​​​方法给路由添加​​ModifyResponseBody​​过滤器。

Spring Cloud Alibaba:Gateway之路由过滤器工厂(三)_spring cloud_18


其他的路由过滤器工厂在以后的博客中介绍,如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。


标签:http,String,Spring,Alibaba,Cloud,过滤器,org,message,路由
From: https://blog.51cto.com/u_15870611/5838277

相关文章

  • Spring Boot:自定义SpringApplication
    自定义SpringApplication如果​​SpringApplication​​​的默认值不满足我们的需求,可以创建​​SpringApplication​​实例并对其进行自定义设置,例如,要关闭横幅:packagecom......
  • Spring Boot:热部署
    配置IDEA勾选​​Buildprojectautomatically​​选项。搜索​​Registry​​​(双击​​Shift​​​键),找到并勾选​​compiler.automake.allow.when.app.running​​选项。......
  • Spring Boot:替换Web服务器
    ​​SpringBoot​​​应用包含默认的嵌入式​​Web​​容器。对于​​servlet​​​应用,​​spring-boot-starter-web​​​通过依赖​​spring-boot-starter-tomcat​​​......
  • Spring Boot:HTTP端口
    在​​SpringBoot​​​应用程序中,​​HTTP​​​端口默认为​​8080​​。可以通过​​server.port​​​属性来设置,往配置文件​​application.properties​​中添加以......
  • springBoot实现全局跨域
    importlombok.extern.slf4j.Slf4j;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.s......
  • spring boot 项目,使用 maven 构建工具打包的两种方法
    根据pom.xml文件指定的打包格式,打包成对于格式的包。如下:<packaging>war</packaging>使用IDEA的终端直接操作(或者cmd)。第一种方式:输入​​mvnpackage​​:打包成......
  • Spring Boot:The new driver class is com.mysql.cj.jdbc.Driver
    以前使用的是​​5.1.31​​​的​​mysql​​​驱动,后面使用​​SpringBoot​​​默认的​​mysql​​驱动,启动就报错了:Loadingclass`com.mysql.jdbc.Driver'.Thisis......
  • springmvc 整合 camunda
    参考官网:ProcessEngine配置|docs.camunda.org 一POM注意:1低版本c3p0会报错:Methodcom/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z千万记得要删除Ta......
  • 自定义SpringMVC(仅用学习)
    自定义MVC有两大核心:1.AppListener程序一启动,监听器就会对程序进行监听,此时会去获取config从而找到controller路径(在使用web项目时,web.xml需要先配置config信息)、再通......
  • 使用 Spring Boot 进行开发
    本节更详细地介绍了如何使用SpringBoot。它涵盖了诸如构建系统、自动配置以及如何运行应用程序等主题。我们还介绍了一些SpringBoot最佳实践。尽管SpringBoot没有什......