0

我有一个 Vertx API,用户可以在其中执行 http POST,但我想限制来自垃圾邮件 API 调用的同一个人/IP 地址,例如在他们可以再次执行之前限制 30 秒的速率。

我可以在哪里以及如何在我的 vertx API 代码中实现这个速率限制?

这是我的开胃菜:

public class Starter extends AbstractVerticle {
private static final Logger LOGGER = Logger.getLogger(Starter.class.getSimpleName());
private static final String HTTP_PORT = "http.port";
private static final Integer HTTP_FALLBACK_PORT = 8000;

public Starter() {
}

@Override
public void start(Promise<Void> startPromise) throws ParseException {
    vertx
        .createHttpServer()
        .requestHandler(buildRoutes(enableCors()))
        .listen(config().getInteger(HTTP_PORT, HTTP_FALLBACK_PORT),
            asyncResult -> listener(asyncResult, startPromise));


}

private Router buildRoutes(final Router router) throws ParseException {
    new MovieApi(router);
    router.errorHandler(500, this::handle500Error);
    return router;
}

private void handle500Error(RoutingContext routingContext) {
    LOGGER.log(Level.SEVERE, "Internal Server Error", routingContext.failure());
}

private Router enableCors() {
    var router = Router.router(vertx);
    router.route().handler(CorsHandler.create(".*.")
                               .allowedHeader("x-requested-with")
                               .allowedHeader("Access-Control-Allow-Origin")
                               .allowedHeader("origin")
                               .allowedHeader("Content-Type")
                               .allowedHeader("accept")
                               .allowedMethod(HttpMethod.GET)
                               .allowedMethod(HttpMethod.POST)
                               .allowedMethod(HttpMethod.DELETE)
                               .allowedMethod(HttpMethod.PUT));
    router.route().handler(BodyHandler.create());
    return router;
}

@Override
public void stop(Promise<Void> endFuture) {
    vertx.close(completionHandler -> endFuture.complete());
}

private void listener(final AsyncResult<HttpServer> res, Promise<Void> startPromise) {
    if (res.succeeded()) {
        startPromise.complete();
        LOGGER.log(Level.INFO,
            () -> String.format("Server is listening on port: %s", res.result().actualPort()));
    } else {
        startPromise.fail("Failed to start http server");
        LOGGER.log(Level.INFO,
            () -> String.format("Failed to bind on port: %s", config()
                                                                  .getInteger(HTTP_PORT, HTTP_FALLBACK_PORT)));
    }
}

public static void main(String... args) {
    var vertx = Vertx.vertx();
    vertx.deployVerticle(Starter.class.getName());
}

}

4

1 回答 1

2

Vert.x 处理程序只是责任链模式的一个实现。您可以自己轻松实现一个:

...
router.route().handler(BodyHandler.create());
router.route().handler(new MyRateLimiter());
...

该类MyRateLimiter将必须实现一个方法:

void handle(RoutingContext rc)

如何实现速率限制的逻辑完全取决于您。您可以使用 TTL 将 IP 存储在 Redis 中,或者使用共享地图或其他适合您的解决方案。

如果一切正常,然后调用rc.next()

如果你想限制速率,你可以使用rc.fail(503),例如。

于 2021-08-13T14:02:21.867 回答