web-dev-qa-db-ja.com

ApacheHttpClientを使用して応答本文をストリーミングする方法

長さがないオクテットストリーミングを実行するために必要なAPIがあります。これは、リアルタイムデータのストリームにすぎません。私が抱えている問題は、リクエストを行うと、入力ストリームに情報を読み込む前にコンテンツの終わりを待とうとしているように見えることですが、コンテンツの終わりが表示されず、NoHttpResponse例外でタイムアウトします。以下は私のコードの簡略版です:

private static HttpPost getPostRequest() {
    // Build uri
    URI uri = new URIBuilder()
            .setScheme("https")
            .setHost(entity.getStreamUrl())
            .setPath("/")
            .build();

    // Create http http
    HttpPost httpPost = new HttpPost(uri);

    String nvpsStr = "";
    Object myArray[] = nvps.toArray();
    for(int i = 0; i < myArray.length; i ++) {
        nvpsStr += myArray[i].toString();
        if(i < myArray.length - 1) {
            nvpsStr += "&";
        }
    }

    // Build http payload
    String request = nvpsStr + scv + streamRequest + "\n\n";
    // Attach http data
    httpPost.setEntity(new StringEntity(URLEncoder.encode(request,"UTF-8")));

    return httpPost;
}

// Where client is simply
// private static final CloseableHttpClient client = HttpClients.createDefault();
private static runPostRequest (HttpPost request) {
    CloseableHttpResponse response = client.execute(request);
    try {
        HttpEntity ent = response.getEntity();
        InputStream is = ent.getContent();
        DataInputStream dis = new DataInputStream(is);
        // Only stream the first 200 bytes
        for(int i = 0; i < 200; i++) {
            System.out.println(( (char)dis.readByte()));
        }

    } finally {
        response.close();
    }
}
8
Dr.Knowitall

編集2

したがって、threads/runnables/Handlersに慣れておらず、Android AsyncTask)に慣れていない場合は、HttpUrlConnectionに直接移動します(基本的にGoogleが言うので、ApacheHttpClientで演習全体を削除します)そのHttpUrlConnectionはストリーミング応答をサポートし、それは機能します!)

ヘッダーのダンプなど、すべての詳細をインストルメント化するのは簡単ではないかもしれません。しかし、通常のストリーミング応答オブジェクトでは、それはうまくいくはずだと思います。HttpsUrlConnectionコードサンプルについては編集3を参照してください。

EndEdit2

どの「ストリーム」プロトコルが使用されているか(プログレッシブダウンロードまたはHTTPストリーミング)の質問からは明らかではありませんORクライアントでストリーミング応答を実際にどのように管理しているか。

クライアントとサーバーが何に同意しているかを正確に確認するために、接続からヘッダーをダンプすることをお勧めしますか?

UIスレッド(AsyncTaskまたはハンドラーのコールバック部分のいずれか)がオフになっていると想定しています。それが正確でない場合は、少しリファクタリングする必要があるかもしれません。

Apache HttpClient4.3.5以降で使用されているHTTPストリームを想定

応答のヘッダーに長さがない場合は、HTTP 1.1で「チャンク」応答を実行しており、「最後のチャンク」を取得するか、ストリームまたは接続のいずれかを閉じることを決定するまで、バッファーを読み取る必要があります。 :

サーバーは送信(ストリーミング)を開始するだけで、クライアントは、エンティティコンテンツの生成に関する詳細なApacheノートに従って、バッファを使用してHTTP応答から取得する「input-stream」を処理する必要があります。

30秒のソケットタイムアウトがアクティブストリームをプリエンプトするかどうかを覚えていませんか? Apacheでは、ソケットタイムアウトとreadタイムアウトの個別の設定がビルダーに存在することを覚えておいてください。サーバーが応答を提供している間、ソケットを閉じたり、読み取り可能なストリームの使用可能なバイトを待機してタイムアウトしたりしないでください。

とにかく、クライアント側のハンドラーは、バッファーに読み込まれたものを検査することによって、ストリームがどのように終了するかを認識する必要があります...

配置されているプロトコルが「続行」および「チャンク」の場合、クライアントの応答ハンドラーは、 http仕様 からLAST-CHUNKが検出されるまで、ストリームハンドラーループ内にある必要があります。

 response.getEntity().getContent() 

'last-chunk'まで応答のストリームを処理するために必要な参照を提供する必要があります...

私はあなたがすべきだと思います ここを読んでください 応答の「最後のチャンク」で終わるために複数の読み取りが必要になるバッファリングされたエンティティを消費する方法について。 HttpURLConnectionが簡単なもう1つの理由です...

'last-chunk'に一致するバイトによってENDが通知されるまで、バッファリングされた読み取りを処理するループを実行します。

次に、エンティティと再利用可能な接続の消費に関する詳細なApacheノートに従って、ストリームまたは接続のいずれかを閉じます。

[〜#〜] edit [〜#〜]ApacheHttpClientのストリーミング応答のコード

'ハンドラーのコールバックまたはasyncTask内

 request.execute();
...

 processStreamingEntity(response.getEntity());
 response.close();

//implement your own wrapper as mentioned in Apache docs

    private void processStreamingEntity(HttpEntity entity) throws IOException {
        InputStreamHttpEntityHC4 bufHttpEntity = new InputStreamHttpEntityHC4(entity);
        while not bufHttpEntity.LAST_CHUNK {
            handleResponse(bufHttpEntity.readLine())
}

編集3

そのようにすると、HttpURLConnectionバージョン。 (MessageHandlerを使用しますが、これはストリーミングspeachの例からのものであり、テキストからの単語がここでUIに返送されるため、バイトをその場で消費する可能性があります)

private void openHttpsConnection(String urlStr, Handler mhandler) throws IOException {
    HttpsURLConnection httpConn = null;
    String line = null;
    try {
        URL url = new URL(urlStr);
        URLConnection urlConn = url.openConnection();               
        if (!(urlConn instanceof HttpsURLConnection)) {
            throw new IOException ("URL is not an Https URL");
        }               
        httpConn = (HttpsURLConnection)urlConn;
        httpConn.setAllowUserInteraction(false);
        httpConn.setInstanceFollowRedirects(true);
        httpConn.setRequestMethod("GET");
        httpConn.setReadTimeout(50 * 1000);
        BufferedReader is =
                new BufferedReader(new InputStreamReader(httpConn.getInputStream()));                   

        while ((line = is.readLine( )) != null) {

                Message msg = Message.obtain();
                msg.what=1;  
                msg.obj=line;                       
                mhandler.sendMessage(msg);

        }               
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch( SocketTimeoutException e){
        e.printStackTrace();
    } catch (IOException e) {

        e.printStackTrace();
        Message msg = Message.obtain();
            msg.what=2;
            BufferedInputStream in = new BufferedInputStream(httpConn.getErrorStream());

            line =new String(readStream(in));
            msg.obj=line;
            mhandler.sendMessage(msg);

    }
    finally {httpConn.disconnect();}

}
7
Robert Rowntree