如何使用异步 servlet 修改代理响应?

How do I modify proxy responses using asynchronous servlets?

我正在尝试实现一个异步 servlet,它将接收最终用户的请求,将其传递到后端服务器并获取响应。

到目前为止,这听起来像是 Jetty ProxyServlet 的一个非常标准的应用程序。

现在,不同之处在于我的后端将使用 include 语句(有点像 Server-Side-Includes)进行响应,我需要对其进行解析、查询后端并插入到最终用户响应中的适当位置流。

您将如何实施?我特别好奇在 onResponseContent 回调期间解析和触发中间请求,据我所知,它可能包含也可能不包含完整响应(因此可能只包含 include 语句的一部分)。

为了说明,这是我目前拥有的:

@WebServlet(name = "MyServlet",
        urlPatterns = {"/my/outbounduri/*"},
        initParams = {
                @WebInitParam(name = "proxyTo", value = "/servlet/backend")
        }
)
public class MyHandler extends ProxyServlet {
    @Override
    protected void customizeProxyRequest(HttpServletRequest srequest, 
            HttpServletResponse sresponse ) {
        // add custom headers for the backend
    }

    @Override
    protected void onResponseContent(HttpServletRequest request, 
            HttpServletResponse response, Response proxyResponse, 
            byte[] buffer, int offset, int length, Callback callback) {
        try {
            // instead of passing the content on, we need to catch 
            // include statements
            // response.getOutputStream().write(buffer, offset, length);
            callback.succeeded();
        } catch (Throwable x) {
            callback.failed(x);
        }
    }

    @Override
    protected void onResponseSuccess(HttpServletRequest request, 
            HttpServletResponse response, Response proxyResponse) {
        AsyncContext asyncContext = request.getAsyncContext();
        asyncContext.complete();
    }
}

如果您在内容代理期间修改内容,请使用 Jetty 9.2.8.v20150217 及其新的 org.eclipse.jetty.proxy.AsyncMiddleManServlet

注意:这是全新的功能,在实现中肯定会有一些缺陷。

这是一个专门的 AsyncProxyServlet 旨在简化修改来自客户端的请求内容 and/or 来自远程服务器的响应内容的复杂性。 (当代理的两端有不同的 Transfer-Encoding 时,这尤其复杂)

在您的用例中,从覆盖 AsyncMiddleManServlet.newServerResponseContentTransformer(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse) 开始,让它 return 成为您设计的 ContentTransformer 的新实例,该实例执行此转换所需的逻辑。

实现您自己的 ContentTransformer,它可以在 .transform(ByteBuffer input, boolean finished, List<ByteBuffer> output)

中完成它需要做的事情

尽你所能阅读 input,一旦你有东西要写,就做一个 output.add(modified)。请注意 finished 标志,因为它会让您知道何时收到了最后一位输入内容。

另外注意,如果需要控制客户端请求端到远程服务器端的URL差异,重写String rewriteTarget(HttpServletRequest clientRequest)方法,读取客户端请求信息和return修改远程 URL 字符串。