我有一个Vertx API,用户可以执行http POST,但我想限制相同的人/ip地址从垃圾邮件API调用,像一个30秒的速率限制之前,他们可以再次这样做。
我在哪里以及如何在我的顶点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());
}
}
x处理程序只是责任链模式的一个实现。你自己也可以很容易地实现一个:
...
router.route().handler(BodyHandler.create());
router.route().handler(new MyRateLimiter());
...
MyRateLimiter
类必须实现一个方法:
void handle(RoutingContext rc)
如何实现速率限制的逻辑实际上取决于您。你可以用TTL将ip存储在Redis中,或者使用共享地图,或者其他适合你的解决方案。
如果一切正常,则调用rc.next()
如果需要限速,可以使用rc.fail(503)
,例如: