在 Spring WebTestClient 中有多个请求 IP
Having multiple request IPs in Spring WebTestClient
我将在我的 Spring Web 应用程序中引入 Bucket4J。可以在此处找到基本测试设置:
Bucket4J 提供基于 IP 的速率限制 - 因此每个 IP 都有自己的令牌池。这可以通过在配置中添加 expression: "getRemoteAddress()"
来完成:
bucket4j:
enabled: true
filters:
- metrics:
types:
- consumed-counter
- rejected-counter
- cache-name: buckets
filter-method: webflux
url: .*
filter-order: 1
rate-limits:
- bandwidths:
- capacity: 1
time: 10
unit: seconds
expression: "getRemoteAddress()"
我很难弄清楚如何以编程方式测试 filter by IP
是否正常工作。
单个IP的测试是这样的:
@ActiveProfiles("test")
@SpringBootTest
class RateLimitTest(
@Autowired val context: ApplicationContext
) {
@Test
fun `FAILS with status code 429 if rate limit is exceeded`() {
// arrange
val client = WebTestClient
.bindToApplicationContext(context)
.configureClient()
.build()
// ac
client.get()
.uri("/api/someendpoint")
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
client.get()
.uri("/api/someendpoint")
.exchange()
.expectStatus().isEqualTo(HttpStatus.TOO_MANY_REQUESTS)
.expectBody().jsonPath("error", "Too many requests!")
// assert
}
验证多个 IP/IP 速率限制的行为的测试应该是什么样的?
FAILS with status code 429 if rate limit * for IP * is exceeded
其实我的做法大体上是错误的。有问题的应用程序在负载均衡器后面,因此查询 getRemoteAddress()
只会给我负载均衡器的 IP。
我不得不使用 header X-FORWARDED-FOR
这使得为其创建测试变得非常容易
bucket4j:
enabled: true
filters:
- metrics:
types:
- consumed-counter
- rejected-counter
- cache-name: buckets
filter-method: webflux
url: ^(/api/someendpoint).*
filter-order: 1
rate-limits:
- bandwidths:
- capacity: 1
time: 10
unit: seconds
expression: "getHeaders()['X-FORWARDED-FOR']"
对此的测试是
@Test
fun `SUCCESSFULLY rate by X-FORWARDED-FOR header`() {
// arrange
val endpoint = "/api/someendpoint"
// act
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.1")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.2")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.1")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isEqualTo(HttpStatus.TOO_MANY_REQUESTS)
.expectBody().jsonPath("error", "Too many requests!")
// assert
}
我将在我的 Spring Web 应用程序中引入 Bucket4J。可以在此处找到基本测试设置:
Bucket4J 提供基于 IP 的速率限制 - 因此每个 IP 都有自己的令牌池。这可以通过在配置中添加 expression: "getRemoteAddress()"
来完成:
bucket4j:
enabled: true
filters:
- metrics:
types:
- consumed-counter
- rejected-counter
- cache-name: buckets
filter-method: webflux
url: .*
filter-order: 1
rate-limits:
- bandwidths:
- capacity: 1
time: 10
unit: seconds
expression: "getRemoteAddress()"
我很难弄清楚如何以编程方式测试 filter by IP
是否正常工作。
单个IP的测试是这样的:
@ActiveProfiles("test")
@SpringBootTest
class RateLimitTest(
@Autowired val context: ApplicationContext
) {
@Test
fun `FAILS with status code 429 if rate limit is exceeded`() {
// arrange
val client = WebTestClient
.bindToApplicationContext(context)
.configureClient()
.build()
// ac
client.get()
.uri("/api/someendpoint")
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
client.get()
.uri("/api/someendpoint")
.exchange()
.expectStatus().isEqualTo(HttpStatus.TOO_MANY_REQUESTS)
.expectBody().jsonPath("error", "Too many requests!")
// assert
}
验证多个 IP/IP 速率限制的行为的测试应该是什么样的?
FAILS with status code 429 if rate limit * for IP * is exceeded
其实我的做法大体上是错误的。有问题的应用程序在负载均衡器后面,因此查询 getRemoteAddress()
只会给我负载均衡器的 IP。
我不得不使用 header X-FORWARDED-FOR
这使得为其创建测试变得非常容易
bucket4j:
enabled: true
filters:
- metrics:
types:
- consumed-counter
- rejected-counter
- cache-name: buckets
filter-method: webflux
url: ^(/api/someendpoint).*
filter-order: 1
rate-limits:
- bandwidths:
- capacity: 1
time: 10
unit: seconds
expression: "getHeaders()['X-FORWARDED-FOR']"
对此的测试是
@Test
fun `SUCCESSFULLY rate by X-FORWARDED-FOR header`() {
// arrange
val endpoint = "/api/someendpoint"
// act
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.1")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.2")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("X-Rate-Limit-Remaining", "0")
WebTestClient
.bindToApplicationContext(context)
.configureClient()
.defaultHeader("X-FORWARDED-FOR", "1.1.1.1")
.build()
.get()
.uri(endpoint)
.exchange()
.expectStatus().isEqualTo(HttpStatus.TOO_MANY_REQUESTS)
.expectBody().jsonPath("error", "Too many requests!")
// assert
}