如何将post语句写入压缩的HttpUrlConnection?

时间:2014-02-24 18:40:13

标签: java android post gzip httpurlconnection

我一直被告知你应该将数据压缩以提高效率。在输入大小上,这相对容易,如下所示:

HttpURLConnection urlConnection=(HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestProperty("Accept-Encoding", "gzip");
InputStream instream=urlConnection.getInputStream();
Map<String, List<String>> headers = urlConnection.getHeaderFields();
List<String> contentEncodings=headers.get("Content-Encoding");
boolean hasGzipHeader=false;
if (contentEncodings!=null) {
    for (String header:contentEncodings) {
        if (header.equalsIgnoreCase("gzip")) {
            hasGzipHeader=true;
            break;
        }
    }
}
if (hasGzipHeader) {
    instream = new GZIPInputStream(instream);
}

输出端看起来有点棘手。我已经找到了如何发送一般的Post语句输出,如下所示:

HttpsURLConnection conn = (HttpsURLConnection) url
        .openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Accept-Encoding", "gzip");
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
        "application/x-www-form-urlencoded");

OutputStream os = conn.getOutputStream();
os.write(getQuery(results).getBytes(Charset.forName("UTF8")));

private String getQuery(List<BasicNameValuePair> params)
        throws UnsupportedEncodingException {
    StringBuilder result = new StringBuilder();
    boolean first = true;
    for (BasicNameValuePair pair : params) {
        if (first)
            first = false;
        else
            result.append("&");

        result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
        result.append("=");
        result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
    }
    return result.toString();
}

但我无法弄清楚如何获得输出流gziped,如果它甚至可能。我无法弄清楚如何判断服务器是否接受连接,以及如何告诉服务器数据已压缩。发送编码数据非常容易,如下所示:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream(baos);
gzipStream.write(getQuery(results).getBytes(
        Charset.forName("UTF8")));
os.write(baos.toByteArray());

1 个答案:

答案 0 :(得分:8)

是的,对于输入(下载),HttpURLConnection的Android实现透明地执行gunzip。但是对于输出(上传),这不是自动完成的。客户端无法知道服务器是否支持压缩。因此,您必须手动执行此操作,并且必须确保服务器了解请求。

您可以在DavidWebb找到一个示例。

gzip有效负载的代码:

static byte[] gzip(byte[] input) {
    GZIPOutputStream gzipOS = null;
    try {
        ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
        gzipOS = new GZIPOutputStream(byteArrayOS);
        gzipOS.write(input);
        gzipOS.flush();
        gzipOS.close();
        gzipOS = null;
        return byteArrayOS.toByteArray();
    } catch (Exception e) {
        throw new WebbException(e); // <-- just a RuntimeException
    } finally {
        if (gzipOS != null) {
            try { gzipOS.close(); } catch (Exception ignored) {}
        }
    }
}

您必须设置以下标题:

connection.setRequestProperty("Content-Encoding", "gzip");