简书链接:163音乐点歌乱码分析以及解决办法
文章字数:414,阅读全文大约需要1分钟
习惯抓包然后把所有请求头弄上去,结果电脑上正常,手机模拟访问竟然是乱码的,我就郁闷了,竟然是http的常识坑死了我,还以为是163有什么高级手段呢。
解决方法是删除Accept-Encoding的模拟,或者自己手动解码.

1
2
3
4
5
6
map.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36.35068264 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36");
map.put("Cache-Control", "max-age=0");
map.put("Host", "s.music.163.com");
map.put("Connection", "close");
map.put("Accept-Encoding", "gzip, deflate, sdch");
map.put("Accept", "application/json; charset=utf-8");

大致猜测可能是Accept,或者Accept-Encoding的问题后面搜索了一下,所以new一个GZIPInputStream就可以解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

private static String zipInputStreamParse(InputStream is) throws IOException {
GZIPInputStream gzip = new GZIPInputStream(is);
BufferedReader in = new BufferedReader(new InputStreamReader(gzip, "UTF-8"));
StringBuffer buffer = new StringBuffer();
String line;
while ((line = in.readLine()) != null)
buffer.append(line + "\n");
is.close();
return buffer.toString();
}

private static String zipInputStreamParse(String out) throws IOException {
ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(out.getBytes());
return zipInputStreamParse(out);
}

结果又出现新的错误了

format (magic number ef1f) ``` 百度了一下说这样可以解决问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
```
public String unZip(String zipped) throws DataFormatException, IOException {
byte[] bytes = zipped.getBytes("WINDOWS-1251");
Inflater decompressed = new Inflater();
decompressed.setInput(bytes);

byte[] result = new byte[100];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

while (decompressed.inflate(result) != 0)
buffer.write(result);

decompressed.end();

return new String(buffer.toByteArray(), charset);
}

实际上上面的代码也不能解决问题,上面我也copy错代码了,是压缩的代码,而并非是解压的代码,另外压缩的流如果强制转换为字符串然后再转回去会出现问题,所以我的简单的网络请求框架需要改写 判断请求头是否包含zip如果包含就进行自动解码操作.
原生的解压已经是字符串了,,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public static byte[] uncompress(InputStream in) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
} catch (IOException e) {
Log.w(TAG, "gzip uncompress error.", e);
}

return out.toByteArray();
}
``
所以在原来的封装简易框架上加了一个判断问题完美解决。不过现在要解决的问题是QQ音乐卡片不支持?拼接而且必须是mp3等格式结尾,尴尬

第三方框架okhttp的gzip解决方案

public class GzipRequestInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null || originalRequest.header(“Content-Encoding”) != null) {
return chain.proceed(originalRequest);
}

    Request compressedRequest = originalRequest.newBuilder()
            .header("Content-Encoding", "gzip")
            .method(originalRequest.method(), gzip(originalRequest.body()))
            .build();
    return chain.proceed(compressedRequest);
}

private RequestBody gzip(final RequestBody body) {
    return new RequestBody() {
        @Override
        public MediaType contentType() {
            return body.contentType();
        }

        @Override
        public long contentLength() {
            return -1; // 无法提前知道压缩后的数据大小
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
            body.writeTo(gzipSink);
            gzipSink.close();
        }
    };
}

}