在项目中使用了 retrofit 和 OkHttp 之后,服务端返回的数据都是被压缩的,导致 OkHttp 不能解析数据 问题排查在此之前,通过调用 API 服务端下发的数据都是 gzip 压缩的,但是 response 的 header 里面并没有Content-Encoding:gzip 的 header 头。以前在使用 HttpURLConnection 类的时候,都是直接写解压代码解压 response 数据流的(后面有代码)。 通过查 OkHttp 的说明,OkHttp 其实是会自动根据是否有这个 gzip 的头来判断是否需要解压 response 数据。 基于此,我让服务端在 response 的 header 里加上了 response.addHeader("Content-Encoding", "gzip”); 的头,至此,Android 这边问题解决已解决。然而 iOS 那边出现了数据无法解压的错误,具体错误描述是:当他们对返回的数据进行 gzip 解压时发现不能顺利解压。问题排查时发现,他们拿到的 response 数据已经被解压好的,当通过调用自己实现的解压方法后,数据就异常了。所以,初步断定,服务端在加了 gzip 头之后,下发的数据就没有被压缩了。 debug 经过依照这个思路,我们服务端去 check 为何加了头之后数据就没有被压缩。我在 Android 端联调时通过使用 FaceBook 的 Stetho工具(Chrome)进行网络抓包的时候时发现,数据确实是没有被压缩的。 和服务端联调一个下午加一个晚上无果之后(绑 host,切 IP 等各种方法都尝试了),服务端同学提出数据确实是被压缩了,debug 打出来的 log 数据已经证明了,而且发现 Chrome 在网络调试时会对有 gzip 的头的数据进行自动解压的。 基于此,我在 Android 里使用 HttpURLConnection 类进行手动 debug,代码如下: int responseCode = httpURLConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { //un gzip in = httpURLConnection.getInputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int len1; byte[] buffer1 = new byte[1024]; while ((len1 = in.read(buffer1)) != -1) { byteArrayOutputStream.write(buffer1, 0, len1); } in.close(); byteArrayOutputStream.close(); final String str1 = new String(byteArrayOutputStream.toByteArray(), "utf-8"); Debug.i_MrFu("未做解压的数据 = " + str1); //do gzip in = new GZIPInputStream(httpURLConnection.getInputStream()); ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); int len; byte[] buffer = new byte[1024]; while ((len = in.read(buffer)) != -1) { arrayOutputStream.write(buffer, 0, len); } in.close(); arrayOutputStream.close(); final String str = new String(arrayOutputStream.toByteArray(), "utf-8"); Debug.i_MrFu("做了解压的数据 = " + str); } 最终发现,确实下发的数据是压缩过的。此时,iOS 也找到了问题的所在,iOS 的 NSURLConnection 类会针对有 gzip 头的 response 进行自动解压。所以他们 debug 时拿到的 byte[] 其实是已经解压好的,看此 issue: NSURLConnection/NSURLRequest gzip support! 结论
|