【问题标题】:Android: how can I make an HTTP HEAD request?Android:如何发出 HTTP HEAD 请求?
【发布时间】:2014-03-20 18:10:16
【问题描述】:

我想发出一个简单的 HTTP HEAD 请求,不使用 keep-alive。

如何在 Android 中做到这一点?

【问题讨论】:

    标签: android http-head


    【解决方案1】:

    使用 HttpClient

    正如 njzk2 建议的那样,HttpClient() 非常简单:

    HttpResponse response = new HttpClient().execute(new HttpHead(myUrl));
    

    但是存在无法关闭连接的问题。通常在 HttpClient 上,您会使用以下方式获取实体:

    HttpEntity entity = response.getEntity();
    

    然后你会从实体获取输入流

    InputStream instream = entity.getContent();
    ...
    instream.close();
    

    通过关闭输入流,连接将关闭。 但是,在 HEAD 请求的情况下,实体似乎是 null(可能是因为 HEAD 请求没有在响应中返回正文),因此无法获取和关闭输入流并且连接不会关闭要么。

    在他回答的最后一次编辑中,njzk2 建议使用AndroidHttpClient,这是HttpClient 的更新实现(API 8),它实际上有一个close() 方法。我没用过,但我想它会很好用。但是,正如 Android 开发团队所建议的那样,HttpUrlConnection 应该是首选的 Android 客户端。

    使用 HttpUrlConnection

    实际上,使用HttpUrlConnection 发出HEAD 请求并确保连接关闭似乎很容易:

        HttpURLConnection urlConnection = null;
        System.setProperty("http.keepAlive", "false");
        try {
            URL url = new URL(stringUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("HEAD");
            urlConnection.getInputStream().close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
    

    【讨论】:

    • 还有entity.consumeContent()
    • 问题是用HttpClient发出HEAD请求时,实体是null
    • 我真的不明白为什么连接会保持打开状态。我已经使用 HttpClient 很长一段时间了,对此我感到非常满意。服务器似乎从未因未关闭的连接而不堪重负。
    • 只要您可以关闭连接,HttpClient 就可以,GET、POST、PUT 都会发生这种情况。但是对于 HEAD 请求,连接不会被客户端关闭,需要被服务器关闭。这意味着服务器端这些连接必须进入 TIME_WAIT 状态,默认情况下持续 60 秒,然后才允许重用相同的套接字。但是,如果连接被客户端关闭,服务器不必在 TIME_WAIT 中锁定这些套接字,可以立即重用它们。
    • 我不明白为什么服务器在发送响应后会保持 HEAD 连接(或任何 HTTP 连接)打开(即当它有最后一个数据包的 TCP 确认时) )
    【解决方案2】:

    琐碎:

    HttpResponse response = new AndroidHttpClient().execute(new HttpHead(myUrl));
    

    通常您会为多个连接使用相同的AndroidHttpClient,然后调用close

    【讨论】:

    • 谢谢!之后会默认关闭连接吗?还是我需要阅读回复?
    • 标头在 HttpResponse 中。你不需要关闭连接。
    • 实际上我可以在服务器上验证(使用“netstat”)连接保持状态为“ESTABLISHED”。有没有办法使用HttpDefaultClient 明确关闭连接?在HttpUrlConnection 上,您可以明确关闭与disconnect() 的连接。是否可以使用HttpUrlConnection 发出 HEAD 请求?
    • 其实有一个AndroidHttpClient有一个close方法释放所有连接。
    • 我发现用HttpUrlConnection设置HEAD请求其实很简单,你只需要加上:httpUrlConnection.setRequestMethod("HEAD");
    【解决方案3】:

    适用于普通 Java 和 Android

    如果参数 if_modified_since 不为零,我正在使用一些标准 Java 代码来测试资源是否存在,同时检查资源是否已更改。

            URL url = new URL(adr);
            try {
                URLConnection con = url.openConnection();
                con.setIfModifiedSince(if_modified_since);
                if (con instanceof HttpURLConnection) {
                    /* Workaround for https://code.google.com/p/android/issues/detail?id=61013 */
                    con.addRequestProperty("Accept-Encoding", "identity");
                    ((HttpURLConnection) con).setRequestMethod("HEAD");
                    int response = ((HttpURLConnection) con).getResponseCode();
                    if (response == HttpURLConnection.HTTP_UNAVAILABLE)
                        return false;
                    if (response == HttpURLConnection.HTTP_NOT_MODIFIED)
                        return false;
                }
                if (if_modified_since != 0) {
                    long modified = OpenOpts.getLastModified(con);
                    if (modified != 0 && if_modified_since >= modified)
                        return false;
                }
                InputStream in = con.getInputStream();
                in.close();
                return true;
            } catch (FileNotFoundException x) {
                return false;
            } catch (UnknownHostException x) {
                return false;
            } catch (SocketException x) {
                return false;
            }
    

    有趣的是,代码需要一个 con.getInputStream() 并且我在这里没有遇到一些错误。但是我需要一些帮助代码,以适应指向 JAR 的 URI。帮助代码是:

         private static long getLastModified(URLConnection con) 
                        throws IOException {
        if (con instanceof JarURLConnection) {
            return ((JarURLConnection) con).getJarEntry().getTime();
        } else {
            return con.getLastModified();
        }
    }
    

    代码可以通过一些专门化来进一步优化,如果 URI 是 schema file: ,然后可以直接做 File.exists() 和 File.getLastModified()。

    我们这里没有抛出 ServiceUnvailable 异常,我们基本上假设外部代码会捕获一个 IOException 然后假设一个 false getHead() 的结果。

    【讨论】:

      猜你喜欢
      • 2019-10-20
      • 2021-07-20
      • 2010-09-11
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      相关资源
      最近更新 更多