在 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

}