【问题标题】:HttpClient: Determine empty entity in responseHttpClient:在响应中确定空实体
【发布时间】:2013-06-09 23:58:57
【问题描述】:

我想知道如何确定一个空的 http 响应。 对于空的 http 响应,我的意思是,http 响应只会设置一些标头,但包含一个空的 http 正文。

例如:我对网络服务器执行 HTTP POST,但网络服务器只会返回我的 HTTP POST 的状态代码,而不会返回其他任何内容。

问题是,我在 apache HttpClient 之上编写了一个小的 http 框架来进行自动 json 解析等。所以这个框架的默认用例是发出请求并解析响应。但是,如果响应不包含数据,如上例所述,我将确保我的框架跳过 json 解析。

所以我做了这样的事情:

HttpResponse response = httpClient.execute(uriRequest);
HttpEntity entity = response.getEntity();
if (entity != null){
    InputStream in = entity.getContent();
    // json parsing
}

但是实体总是 != null。并且检索到的输入流也是!= null。有没有简单的方法可以判断http body是否为空?

我看到的唯一方法是服务器响应包含设置为 0 的 Content-Length 标头字段。 但并不是每个服务器都设置了这个字段。

有什么建议吗?

【问题讨论】:

    标签: java android httpclient


    【解决方案1】:

    HttpClientgetEntity() 可以返回null。见the latest samples

    然而,empty 实体和 no 实体之间是有区别的。听起来你有一个 empty 实体。 (对不起,迂腐——只是 HTTP 是迂腐的。:) 关于检测空实体,您是否尝试过从实体输入流中读取?如果响应是一个空实体,您应该立即得到一个 EOF。

    您是否需要在不从实体主体中读取任何字节的情况下确定实体是否为空?根据上面的代码,我不认为你这样做。如果是这种情况,您可以将实体 InputStream 包装为 PushbackInputStream 并检查:

    HttpResponse response = httpClient.execute(uriRequest);
    HttpEntity entity = response.getEntity();
    if(entity != null) {
        InputStream in = new PushbackInputStream(entity.getContent());
        try {
            int firstByte=in.read();
            if(firstByte != -1) {
                in.unread(firstByte);
                // json parsing
            }
            else {
                // empty
            }
        }
        finally {
            // Don't close so we can reuse the connection
            EntityUtils.consumeQuietly(entity);
            // Or, if you're sure you won't re-use the connection
            in.close();
        }
    }
    

    最好不要将整个响应读入内存,以防万一它很大。此解决方案将使用常量内存(4 字节:) 测试是否为空。

    编辑<pedantry> 在 HTTP 中,如果请求没有 Content-Length 标头,则应该有 Transfer-Encoding: chunked 标头。如果也没有 Transfer-Encoding: chunked 标头,那么您应该有 no 实体而不是 empty 实体。 </pedantry>

    【讨论】:

    • 太棒了,谢谢! PushbackInputStream 是关键,否则输入流将被消耗用于检查,不能用于读取真实数据。非常感谢!
    • 很高兴它很有用! PushbackInputStream超级很有用。
    • 在我的情况下,我总是得到 java.net.SocketException: Connection reset 一旦我尝试从内容长度未知的响应的输入流中读取。所以我想使用 PushbackInputStream 不是一种足够通用的方法。检查 Content-Length 和 Transfer-Encoding 标头似乎是处理问题的正确方法。
    【解决方案2】:

    我建议使用EntityUtils 类来获取字符串形式的响应。如果返回空字符串,则响应为空。

    String resp = EntityUtils.toString(client.execute(uriRequest).getEntity())
    if (resp == null || "".equals(resp)) {
        // no entity or empty entity
    } else {
        // got something
        JSON.parse(resp);
    }
    

    这里的假设是,为了代码的简单性和可操作性,您不需要区分空实体和无实体,并且如果有响应,您无论如何都需要阅读它。

    【讨论】:

    • 还是谢谢你,但我更喜欢使用输入流,因为我也解析像图像这样的二进制数据
    • 如果参数为空,EntityUtils.toString 也会抛出异常。有时这不是适当的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    相关资源
    最近更新 更多