web-dev-qa-db-ja.com

Spring MVCでHTTPリクエストをプロキシする方法は?

SpringMVC上に構築されたアプリケーションがあります。

次のようにリクエストを処理する単純なプロキシを作成したいと思います。

  1. 同じHTTPリクエストを特定のサーバーに送信する
  2. この特定のサーバーからHTTP応答をキャプチャする
  3. 要求しているクライアントに同じ答えを返す

これが私がこれまでに得たものです:

public void proxyRequest(HttpServletRequest request, HttpServletResponse response) {
    try {
        HttpUriRequest proxiedRequest = createHttpUriRequest(request);
        HttpResponse proxiedResponse = httpClient.execute(proxiedRequest);
        writeToResponse(proxiedResponse, response);
    } catch (URISyntaxException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void writeToResponse(HttpResponse proxiedResponse, HttpServletResponse response){
    for(Header header : proxiedResponse.getAllHeaders()){
        response.addHeader(header.getName(), header.getValue());
    }
    OutputStream os = null;
    InputStream is = null;
    try {
        is = proxiedResponse.getEntity().getContent();
        os = response.getOutputStream();
        IOUtils.copy(is, os);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

private HttpUriRequest createHttpUriRequest(HttpServletRequest request) throws URISyntaxException{
    URI uri = new URI(geoserverConfig.getUrl()+"/wms?"+request.getQueryString());

    RequestBuilder rb = RequestBuilder.create(request.getMethod());
    rb.setUri(uri);

    Enumeration<String> headerNames = request.getHeaderNames();
    while(headerNames.hasMoreElements()){
        String headerName = headerNames.nextElement();
        String headerValue = request.getHeader(headerName);
        rb.addHeader(headerName, headerValue);
    }

    HttpUriRequest proxiedRequest = rb.build();
    return proxiedRequest;
}

それは問題なく動作しますが、すべての場合ではありません。 Chromeのネットワークモニターをチェックインしましたが、このプロキシを使用しているリクエストの一部が失敗しました。

失敗した要求応答のサンプルのヘッダーは次のとおりです。

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Disposition: inline; filename=JEDN_EWID.png
Transfer-Encoding: chunked
Date: Thu, 16 Jul 2015 10:31:49 GMT
Content-Type: image/png;charset=UTF-8
Content-Length: 6727

成功したリクエストレスポンスのサンプルのヘッダーは次のとおりです。

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Disposition: inline; filename=JEDN_EWID.png
Transfer-Encoding: chunked
Date: Thu, 16 Jul 2015 10:31:49 GMT
Content-Type: image/png;charset=UTF-8
Transfer-Encoding: chunked

さらにChromeはコンソールでエラーをスローします:

GET http://localhost:8080/<rest of url> net::ERR_INVALID_CHUNKED_ENCODING

私がプロキシしているリクエストはWMSGetMapリクエストであり、私のプロキシはそれらを非表示のGeoserverに転送しています。失敗したリクエストは、すべて空の透明な512x512.png画像を返す必要があることに気づきました。成功したものは、透明であるだけでなく、いくつかの色を含む512x512.png画像を返します。

14

サイズが大きくなりすぎると、リモートサーバーがチャンク応答で応答するように見えます。ApacheHttpClientライブラリは、すべてのチャンク要素を1つの大きなHttpResponseに収集しますが、Transfer-Encoding: chunkedヘッダーは残します。

テストできませんでしたが、この問題を取り除くにはTransfer-Encoding: chunkedを除外する必要があります:

private void writeToResponse(HttpResponse proxiedResponse, HttpServletResponse response){
    for(Header header : proxiedResponse.getAllHeaders()){
        if ((! header.getName().equals("Transfer-Encoding")) || (! header.getValue().equals("chunked"))) {
            response.addHeader(header.getName(), header.getValue());
        }
    }
    ...
8
Serge Ballesta