如何使用apache HttpClient传递响应体

Dr.*_*all 8 java httpclient apache-commons-httpclient apache-httpclient-4.x

有一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*ree 7

编辑2

所以,如果你不熟悉线程/ runnables/Handlers并且不熟悉android AsyncTask,我会直接去HttpUrlConnection(用apacheHttpClient删除整个练习因为,基本上googl说HttpUrlConn会支持stream'd响应,它确实有效!)

它可能不像转储标题那样容易检测所有细节.但是,使用正常的流式响应对象,我认为它应该正常工作....请参阅编辑3以获取UrlConn代码示例

EndEdit2

从问题是什么'流'协议被使用(渐进式dwnld | http流)或者如何实际管理客户端上的流式响应不清楚.

建议从连接转储标头,以确切了解客户端和服务器同意的内容?

假设您关闭了UI线程(在asyncTask中或在Handler的回调部分中),因此您可能需要重构一点.

假设http流与apache客户端4.3.5+一起使用

如果响应的头部没有长度,那么你在Http 1.1上做了一个'chunked'响应,你必须读取一个缓冲区直到你得到一个'last-chunk'或者决定关闭流或者Connection :

服务器刚开始发送(流),客户端应该根据生成实体内容的详细apache说明,通过使用缓冲区来处理它从http响应中获得的'input-stream' .

如果30秒的套接字超时会抢占活动流,我不记得了吗?请记住,在apache中,构建器中存在用于套接字超时和READ超时的单独设置.不希望套接字关闭,并且不希望在服务器提供响应时等待可读流的可用字节超时.

无论如何,客户端处理程序只需要通过检查读入缓冲区的内容来了解​​流的结束方式......

如果适当的协议是"继续"和"分块",那么客户端上的响应处理程序应该在流处理程序循环中UNTIL它从http规范中看到LAST-CHUNK .

 response.getEntity().getContent() 
Run Code Online (Sandbox Code Playgroud)

应该为您提供处理响应流所需的参考,直到'last-chunk'...

我想你应该在这里阅读如何使用一个缓冲的实体,在这个实体中需要多个读取才能在响应中的'last-chunk'结束.HttpUrlConn可能更容易的另一个原因......

做一个处理缓冲读取的循环,直到由匹配'last-chunk'的字节表示的END.

然后根据消费实体和可重用连接的详细apache说明CLO流或CONN.

在apache HttpClient中编辑流响应的代码

在'处理程序的回调或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())
}
Run Code Online (Sandbox Code Playgroud)

编辑3

httpUrlConnection版本,如果你去那样.(使用MessageHandler,但你可以使用这些字节,因为这是来自流式语音示例,文本中的单词将被发送回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();}

}
Run Code Online (Sandbox Code Playgroud)