基于 HttpURLConnection 的网络开发总结

1. HttpURLConnection 上传进度

用 HttpURLConnection 做文件上传,会有需要显示上传进度的需求。但是根据官方的文档说明,如下图,HttpURLConnection 在上传数据之前,默认会强制先将请求体缓存在内存中。这样会导致我们上传进度显示不准确。具体现象就是上传进度早早显示上传完成,但是上传网络请求还迟迟未结束。

基于 HttpURLConnection 的网络开发总结

 基于 HttpURLConnection 的网络开发总结

至于解决方式,上面图片中前一句官方给出答案,可以调用 setFixedLengthStreamingMode 方法或者 setChunkedStreamingMode 方法去禁用掉 HttpURLConnection  的上传缓存,这样进度就显示正确。

public void setFixedLengthStreamingMode (int contentLength)
public void setChunkedStreamingMode (int chunklen)

但是 setChunkedStreamingMode 方法并不是被所有服务器都支持,所以我们舍弃了这种方式。

处理示例:

int contentLength = 1;
int uploadLength = 0;
if (listener != null) {
   contentLength = getContentLength(requestParams, boundary, filePaths);
   //禁用 HttpURLConnection 上传缓存
   connection.setFixedLengthStreamingMode(contentLength);
}

......

//在写入的地方调用
out.write(bytes);
if (listener != null) {
   float totalLen = contentLength * 1.0f;
   uploadLength += bytes.length;
   int progress = Math.round((uploadLength / totalLen) * 100);
   listener.onProgress(progress);
}

2. HttpURLConnection 接收服务器返回数据

这里我们需要考虑的点有以下几点:

  • 数据编码
  • 数据类型
  • 数据是否压缩

1. 数据编码以及数据类型

使用正确的编码格式,才能正确接收服务器返回的数据,否则会出现乱码的情况。

获取响应体编码:

//第一种方式,这种方式或者的是相同field的最后一个值
String contentEncoding = connection.getHeaderField("Content-Type");
//第二种方式,这种方式确认是从response中获取。遍历获得
Map<String, List<String>> headerFields = connection.getHeaderFields();

示例值:Content-Type: text/html;charset=UTF-8

2. 数据是否压缩

如果服务器返回的数据是采用了某种压缩格式后传输的,我们直接采用正确的编码直接从数据流读取数据,也会产生乱码。这个时候我们要转成对应压缩数据流去读取。

首先我们先判断服务返回数据是否采用压缩:

String contentEncoding = connection.getHeaderField("Content-Encoding");
InputStream inputStream = connection.getInputStream();
// 处理接口返回gzip数据
if (!TextUtils.isEmpty(contentEncoding) && "gzip".equalsIgnoreCase(contentEncoding)) {
   inputStream = new GZIPInputStream(inputStream);
}

示例 Header : Content-Encoding: gzip

 

基于 HttpURLConnection 的网络开发总结

 

上一篇:Java原生API请求网页


下一篇:Android上不一致的HttpUrlConnection行为 – 如何调试?