如何在 Jetty 过滤器中快速删除请求?

How do I quickly drop a request in a Jetty filter?

我已经编写了一个 Jetty 过滤器来检测和删除来自用户的请求,这些用户正在向端点发送大量请求,有效地 DOSing 其他用户。一旦我检测到它是一个坏演员,我真正想做的是立即放弃请求,并尽可能少地处理。到目前为止我想出的最好的事情是:

HttpServletResponse response = (HttpServletResponse) servletResponse;
if (spamRequest()) {
    response.reset();
    response.setStatus(HttpStatus.TOO_MANY_REQUESTS_429);
    response.flushBuffer();
}

我认为应该用 429 Too Many Requests 和没有正文来回应。但这是一大堆请求,我真的只想短路所有处理并断开连接。抛出异常只会导致 Jetty return 500 并带有一些默认 html 响应,这并不比我当前的解决方案好。

如果使用 Jetty,您可以使用特殊的 non-standard 调用 ...

response.sendError(-1);

这本质上是 javax.servlet.http.HttpServletResponse.sendError(int) 加上 -1 的特殊 "error status code"。

重要提示:以上内容不符合 Servlet 规范,不能在 Jetty 之外工作。

这将中止 Http 通道并关闭连接而不发送响应。

请注意,由于 Servlet 层的展开,您可能会在服务器日志中看到 IOException。

如果你有 RequestLog 这些响应可能看起来很奇怪,所以不要忘记在你调用 sendError(-1) 之前至少做 response.setStatus(HttpStatus.TOO_MANY_REQUESTS_429) 以获得一些有意义的关键在生成的请求日志中。

或者,如果您不喜欢这种行为,请不要忘记在发送有效响应之前指明 Connection: close 以强制服务器在响应后关闭连接。

例如:

if (spamRequest()) {
    response.reset();
    response.setHeader("Connection", "close");
    response.setStatus(HttpStatus.TOO_MANY_REQUESTS_429);
    response.flushBuffer();
}