web-dev-qa-db-ja.com

Javaサーブレットをプロキシとして機能させるためのコード?

2つのJava特定のURLにマップされる単一のサーブレットを持つWebアプリケーション:

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

これらのアプリケーション(私は "バックエンドアプリ"と呼びます)を "プロキシアプリ"(サーブレット)の後ろに置き、最終的にこれら2つのアプリのどちらがクライアント側の要求を処理するかを決定します。

このプロキシWebアプリは、着信HTTPリクエストを受け取り、リクエストを転送する2つの「バックエンドアプリ」(赤または青)を決定します。次に、リクエストは_http://red.example.com/doStuff_(およびRedServlet#doGet(...))によって転送されるか、_http://blue.example.com/doStuff_(およびBlueServlet#doGet(...)によって処理されます)に転送されます。バックエンドアプリから返された応答(ここでもRedServlet#doGet(...)またはBlueServlet#doGet(...))は、プロキシサーブレットに返され、最終的にクライアントに返されます。

つまり、疑似コードでは:

_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...
    }
}
_

これは可能ですか?可能な場合、それを機能させるためにどのように、どのようなコードを記述する必要がありますか?

22
IAmYourFaja

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は、次のオプションを使用して任意に設定されます。

  • include
    これはおそらく実行したいことです。コンテンツをforwardingAdressから応答にロードします。
    • つまり、単一の応答に複数のターゲットを含めることもできます。
    • クライアントはこの手順を理解することすらできず、ターゲットドキュメントを表示できる必要もありません。
  • forward
    _forwardingAddressに転送を送信します。これは、指定されたURLに新しいリクエストを送信するようクライアントに指示します。
    • 開発ツールを備えたブラウザーでそれを行うと、2番目の要求が表示されます。
    • クライアントは、ターゲットURLを表示およびロードできる必要があります。
    • 単一のターゲットにのみ転送できます。

以下のリンクも参照してください。

  • RequestDispatcher javadoc 、特にメモの場合:
    • forwardは、応答がクライアントにコミットされる前(応答本体の出力がフラッシュされる前)に呼び出す必要があります。応答がすでにコミットされている場合、このメソッドはIllegalStateExceptionをスローします。応答バッファ内のコミットされていない出力は、転送の前に自動的にクリアされます。
    • include:要求と応答のパラメータは、呼び出し元のサーブレットのサービスメソッドに渡されたものと同じオブジェクトであるか、またはServletRequestWrapperまたはServletResponseWrapperクラスのサブクラスである必要がありますそれらを包みます。
  • RLRewriteFilterの例
    この例はFilterではなくServletを使用して実装されていますが、動作は同じです(注:この例は私のフレームワークの一部であり、したがって、親クラスです。関連するセクションをご覧ください...)
10
ultimate

承認された回答はまだないので、私はこのリクエストの解決策がApache-http-commonsライブラリを使用してどのように見えるかを記述しようとしています。さらに、筆者にフラッシュを追加することをお勧めします。

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;

}

}

0
ivan.rosina