让 Java servlet 充当代理的代码?

Posted

技术标签:

【中文标题】让 Java servlet 充当代理的代码?【英文标题】:Code to get a Java servlet to act as a proxy? 【发布时间】:2013-05-30 01:21:59 【问题描述】:

我有两个 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(...)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...
    

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

【问题讨论】:

我们使用j2ep... 你需要向后端服务器发出HTTP请求,看看hc.apache.org/httpcomponents-core-ga/httpcore/index.html 我试过github.com/dsmiley/HTTP-Proxy-Servlet,觉得不错 还可以查看 HTTP-Proxy-Servlet 问题 #15 (github.com/mitre/HTTP-Proxy-Servlet/issues/15) 以获取完整示例。 另见Reverse Proxy on Tomcat。 【参考方案1】:

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

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);

...其中useInlcude 设置为您的选择,具有以下选项:

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

请参阅以下链接:

RequestDispatcher javadoc,特别是注释: forward 应该在响应提交给客户端之前调用(在刷新响应正文输出之前)。如果已提交响应,则此方法将引发 IllegalStateException。响应缓冲区中未提交的输出在转发之前会自动清除。 include:请求和响应参数必须是传递给调用 servlet 服务方法的相同对象,或者是包装它们的 ServletRequestWrapper 或 ServletResponseWrapper 类的子类。 URLRewriteFilter example虽然这个例子是使用 Filter 而不是 Servlet 实现的,但行为是相同的(注意:这个例子是我的框架的一部分,因此在父类中包含一些开销。只是看看相关部分...)

【讨论】:

我认为这个解决方案只有在“后端”servlet 部署在同一个应用程序上时才有效。由于红色和蓝色 servlet 部署在不同的主机中,因此可能无法获得其 Context 的 Dispatcher。查看更多解释***.com/questions/4889113/… 你说的forward是错误的:“这会告诉客户端向指定的URL提交一个新的请求。”这不是一个 sendRedirect 命令【参考方案2】:

由于还没有批准的答案,我尝试写下我如何看待这个请求的解决方案,使用 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;


【讨论】:

以上是关于让 Java servlet 充当代理的代码?的主要内容,如果未能解决你的问题,请参考以下文章

仅对来自远程端点的响应起作用的 Servlet 过滤器“代理”

严重: Servlet threw load() exception java.lang.ClassNotFoundException: org.glassfish.jersey.servlet.Se

java servlet获取客户端IP

69期-Java SE-025-动态代理

69期-Java SE-045_JSP-2

69期-Java SE-044_JSP-1