25

我有两个 Java Web 应用程序,它们有一个映射到特定 URL 的 servlet:

red.war/
    WEB-INF/classes
        com.me.myorg.red.RedServlet (maps to http://red.example.com/doStuff)
blue.war/
    WEB-INF/classes
        com.me.myorg.blue.BlueServlet (maps to http://blue.example.com/doStuff)

我想将这些应用程序(我称它们为我的“后端应用程序”)放在一个“代理应用程序”(servlet)后面,该代理应用程序将决定这两个应用程序中的哪一个最终将服务于客户端请求。

此代理 Web 应用程序将接收传入的 HTTP 请求,并确定将请求转发到 2 个“后端应用程序”(红色或蓝色)中的哪一个。然后,请求将被转发到http://red.example.com/doStuff(然后由 处理RedServlet#doGet(...))或http://blue.example.com/doStuff(然后由 处理BlueServlet#doGet(...))。然后从后端应用程序返回的响应(同样是RedServlet#doGet(...)or BlueServlet#doGet(...))将返回到代理 servlet,并最终返回到客户端。

换句话说,在伪代码中:

public class ProxyServlet extends HttpServlet {
    @Override
    public doGet(HttpServletRequest request, HttpServletResponse response) {
        String forwardingAddress;
        if(shouldBeRed(request))
            forwardingAddress = "http://red.example.com/doStuff";
        else
            forwardingAddress = "http://blue.example.com/doStuff";

        PrintWriter writer = response.getWriter();

        writer.write(getResponseFromBackend(forwardingAddress, request));
    }

    private String getResponseFromBackend(String addr, HttpServletRequest req) {
        // Somehow forward req to addr and get HTML response...
    }
}

这可能吗?如果是这样,我需要如何以及编写什么代码才能使其工作?

4

2 回答 2

11

您可以使用 aRequestDispatcher通过以下方式转发您的请求:

RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(forwardingAddress);

// here you have the choice whether to use include(..) or forward(..) see below
if(useInclude)
    dispatcher.include(httpRequest, httpResponse);
else
    dispatcher.forward(httpRequest, httpResponse);

... whereuseInlcude使用以下选项设置为您的选择:

  • 包括
    这可能是您想要做的:将内容加载forwardingAdress到您的响应中。
    • 这意味着您甚至可以在单个响应中包含多个目标。
    • 客户甚至不会意识到这个过程,也不需要能够看到目标文档。
  • 转发 向
    发送转发forwardingAddress。这将告诉客户端向指定的 URL 提交一个新请求。
    • 如果您使用开发者工具在浏览器中执行此操作,您将看到第二个请求。
    • 客户端必须能够查看和加载目标 URL。
    • 您只能转发到单个目标。

请参阅以下链接:

  • RequestDispatcher javadoc,尤其是注释:
    • forward应该在响应提交给客户端之前调用(在刷新响应主体输出之前)。如果已提交响应,则此方法将引发 IllegalStateException。响应缓冲区中未提交的输出在转发之前会自动清除。
    • include:请求和响应参数必须是传递给调用 servlet 服务方法的相同对象,或者是包装它们的 ServletRequestWrapper 或 ServletResponseWrapper 类的子类。
  • URLRewriteFilter 示例
    虽然此示例是使用 aFilter而不是 a实现的,Servlet但行为是相同的(注意:此示例是我的框架的一部分,因此在父类中包含一些开销。只需查看相关部分... )
于 2014-11-17T16:13:55.483 回答
0

由于还没有批准的答案,我尝试写下我如何看待这个请求的解决方案,使用 apache-http-commons 库。另外我建议在writer上添加一个flush。

public class ProxyServlet extends HttpServlet {
@Override
public doGet(HttpServletRequest request, HttpServletResponse response) {
    String forwardingAddress;
    if(shouldBeRed(request))
        forwardingAddress = "http://red.example.com/doStuff";
    else
        forwardingAddress = "http://blue.example.com/doStuff";

    PrintWriter writer = response.getWriter();

    writer.write(getResponseFromBackend(forwardingAddress, request));
    **writer.flush();**
}

private String getResponseFromBackend(String addr, HttpServletRequest req) {
        HttpClient client = new HttpClient();
        HttpMethod method = new GetMethod(url);
        client.executeMethod(method);
        String body=method.getResponseBodyAsString();
        return body;

}

}

于 2018-08-23T12:35:59.373 回答