java使用URLconnection下载文件 getContentLength()为-1 的解决办法

一、起因
APP想要从远程服务器下载一个文件,不想使用网络请求框架,想了解一下原生的实现。于是简单了解了一下URLconnection类的使用,加上参考了网络上的实现,简单实现了文件下载操作。
代码如下

        long downloadLength = 0;
        mDownloadFile = new File(filePath,fileName);
        if (mDownloadFile.exists()){
            downloadLength = mDownloadFile.length();
        }
        //下载文件

        URL url = new URL(downloadUrl);

        URLConnection connection = url.openConnection();
        // 设置允许输入流输入数据到本地
        connection.setDoInput(true);
        // 设置允许输出流输出到服务器
        connection.setDoOutput(true);
        connection.connect();
        mContentLength = connection.getContentLength();
        PrintLogCat.printLogCat(CommonFunction.getClassNameAndMethodNameAndLineNumberInfo()+"contentLength--->"+mContentLength);
        if (mContentLength == 0){
            return DOWNLOAD_FAILED;
        }else if (mContentLength == downloadLength){
            return DOWNLOAD_FINISHED;
        }
        InputStream in = connection.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(in);

        OutputStream os = new FileOutputStream(mDownloadFile);
        //定义整型变量接收读取到文件的大小
        int size ;
        //定义整型变量用来存储累计读取文件长度(大小)
        int length = 0;

        byte[] buffer = new byte[1024];
        // 从输入缓冲区中一次读取1024个字节的文件内容到buf对象中,并将读取大小赋值给size变量,当读取完毕后size=-1,结束循环读取
        while ((size = bis.read(buffer))!= -1){
            length += size;
            //输入流写出数据到文件
            os.write(buffer,0,size);
            int progress =(int)(length*100/mContentLength);
            publishProgress(progress);
        }
        os.close();
        bis.close();
        in.close();

只是截取了一下下载的核心代码。这里为了速度偷了懒部分程序使用了网上的,没有仔细检查网上程序的正确性。
于是在测试验证效果时收到了回报。APP中没有发起下载的操作(网络请求没有得到正确的响应)。当然如果使用网络请求框架的如okgo的会有出现问题会有比较清晰的日志信息。于是开始了寻找问题的旅程。通过添加log信息发现了问题 getContentLength()为-1。
二、问题分析
遇到问题对于菜鸟来说当然是去网上查询前辈大佬的解决方案了,于是开心的上网查找。得到了如下的分析:
1、最近在使用OKhttp下载文件的时候出现了一个奇怪的现象,responsebody.contentLength()获取到的值为-1经常抓包分析,发现服务器会随机的对下发的资源做GZip操作,而此时就没有相应的content-length,解决方法很简单,在Header中加入:Request.Builder().addHeader(“Accept-Encoding”, “identity”)这样强迫服务器不走压缩,问题就得到了解决。 原文链接

2、 链接不正确或者服务器响应的问题 或者ip被屏蔽这个问题经确认,很快的排除了。

3、注意服务器支持的请求方式搜索无果于是使用浏览器输入资源地址,一切正常。于是使用fiddler抓了包。了解如何抓包可参考HTTPS 或手机 APP 接口数据的抓包配置步骤
抓包结果如下:
浏览器:

GET http://xxx/apk/xxx.apk HTTP/1.1
Host: 192.xxx.xxx.xxx:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9


HTTP/1.1 200
Last-Modified: Thu, 27 Jun 2019 02:15:22 GMT
Accept-Ranges: bytes
Content-Type: application/vnd.android.package-archive
Content-Length: 95570633
Date: Thu, 27 Jun 2019 03:21:21 GMT

APP:

POST http://xxx/apk/xxx.apk HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Dalvik/2.1.0 (Linux; U; Android 7.1.1; PRO 6s Build/NMF26O)
Host: 192.xxx.xxx.xxx:8080
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 0


HTTP/1.1 405
Allow: GET, HEAD
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 27 Jun 2019 03:20:15 GMT

c2
{"timestamp":"2019-06-27T03:20:15.897+0000","status":405,"error":"Method Not Allowed","message":"Request method 'POST' not supported","path":"/apk/xxx.apk"}
0

可以看到APP端莫名其妙的变成了POST请求,但是服务器端(Allow: GET, HEAD)不支持POST。所以该请求响应体中没有contentlength属性,这也就是contentlength 返回-1 的原因

于是检查代码,发现添加了

// 设置允许输出流输出到服务器
connection.setDoOutput(true);

去掉后问题解决,通过查看URLconnection 类 上述语句设置为true 就可以获取到服务器的输出流,向服务器发送数据时就需要使用该输出流。于是明白了该语句设置为true就相当于使用了POST请求

三、总结
有空还是要认真理解原理,多动手,多使用工具辅助定位问题。网上查找的结果可作参考,因为多数情况下的异常错误不一定与搜索结果中的情况一致。实现某个功能时页最好能够理解原理,这样有时候能避免很多错误

就网络请求这块异常抓包是最有效的定位问题的方法。

另外大文件(大于100M的文件)没有尝试过,不知道会不会出现新的问题

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Erorrs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值