基于 HttpURLConnection 的网络开发总结
1. 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
参考: