URLConnection 类

URLConnection 类:代表应用程序和URL之间的通信链接,此类的实例可用于读取和写入此URL引用的资源,创建到一个URL的连接的步骤

  1. 通过在 URL 上调用 openConnection 方法创建连接对象
  2. 处理设置参数和一般请求属性
  3. 使用connect方法建立到远程对象的实际连接
  4. 远程对象变为可用,远程对象的头字段和内容变为可访问

参数设置:

  • setAllowUserInteraction:是否允许与用户交互,默认 false
  • setDoInput:URLConnection可用于输入时设置为true,默认为true
  • setDoOutput:URLConnection可用于输出时设置为true,默认为false
  • setIfModifiedSince:将放置If-Modified-Since首部字段中的日期(格林威治标准时间1970年1月1日子夜后的毫秒数)
  • setUseCaches:是否可以在缓存可用时使用缓存,默认为true,表示缓存将被使用;false表示缓存不被使用
  • setConnectTimeout:设置获取连接的超时值,单位为ms
  • setReadTimeout:设置获取读取的超时值,单位为ms
  • setFollowRedirects(boolean set):true,允许跟随重定向

HttpURLConnecton 类

HttpURLConnection 类:可以实现简单的基于URL请求、响应功能
参数值设置:

  • setRequestProperty(String key, String value):在首部设置一个值
  • addRequestProperty(String key, String value):用于添加某个指定首部字段的值
  • InputStream getInputStream():返回从此打开的连接读取的输入流
  • OutputStream getOutputStream():返回写入到此连接的输出流
  • setRequestMethod(String method):设置请求方法
  • getResponseMessage():返回消息响应
  • getResponseCode():返回消息响应码
  • setInstanceFollowRedirects(boolean followRedirects):true,允许跟随重定向
    • 若只是向服务器请求数据,则为HTTP请求方法为GET
    • 若需要向服务器提交数据,必须在先调用setDoOutput(true)。当doOutput属性为true时,请求方法将由GET变为POST

单线程下载器

从给定的地址下载文件,有如下几个要点

  1. 如果传入的 URL 是一个动态网址,需要获取真实的网址,需要设置 URLConnection.setFollowRedirects(boolean set) 或者 HttpURLConnection.setInstanceFollowRedirects(boolean followRedirects) 允许跟随重定向,然后取得真实的下载地址
  2. 在下载文件时传入参数需要设置 Content-Length 属性
  3. 有些下载站可能有防盗链设置,因此最好设置 Referer:网站网址 属性
  4. 为了避免网站的反爬虫机制,最好添加浏览器代理

如果有需要,可以使用 curl 先进行测试:

  • -I:只显示响应头信息
  • -L:跟踪重定向
  • —header “Referer: http://xiazai.zol.com.cn/“ :设置请求头属性,避免防盗链导致跳转到首页

image.png

  1. public class Downloader {
  2. private static HttpURLConnection connection(URL url) throws IOException {
  3. // 1.获取连接
  4. URLConnection urlConnection = url.openConnection();
  5. // 2.获取HttpURLConnection
  6. HttpURLConnection connection = (HttpURLConnection) urlConnection;
  7. // 3.设置基础的连接参数
  8. // 设置Referer参数,避免防盗链
  9. connection.setRequestProperty("Referer", url.getHost());
  10. // 设置用户代理
  11. connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");
  12. // 允许跟踪重定向
  13. connection.setInstanceFollowRedirects(true);
  14. return connection;
  15. }
  16. private static String getFileName(URL url) {
  17. String path = url.getPath();
  18. return path.substring(path.lastIndexOf("/") + 1);
  19. }
  20. private static volatile int count = 0;
  21. private static void downloader(URL url) throws IOException {
  22. /* 获取真实的下载地址 */
  23. HttpURLConnection connection = connection(url);
  24. connection.connect();
  25. // 获取文件大小
  26. long len = connection.getContentLengthLong();
  27. // 获取真实的下载地址
  28. URL urlTruth = connection.getURL();
  29. // 获取文件名
  30. String fileName = getFileName(urlTruth);
  31. // 关闭连接
  32. connection.disconnect();
  33. System.out.println("真实的下载地址:" + urlTruth);
  34. System.out.println("文件名:" + fileName);
  35. System.out.println("文件大小" + len);
  36. /* 开始下载 */
  37. HttpURLConnection conn = connection(urlTruth);
  38. // 设置Content-Length参数
  39. conn.setRequestProperty("Content-Length", String.valueOf(len));
  40. conn.connect();
  41. try (BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
  42. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));) {
  43. byte[] bytes = new byte[1024];
  44. int read = 0;
  45. View view = new View();
  46. // 设置为守护线程
  47. view.setDaemon(true);
  48. view.start();
  49. while ((read = bis.read(bytes)) != -1) {
  50. bos.write(bytes, 0, read);
  51. count += read;
  52. }
  53. bos.flush();
  54. }
  55. }
  56. // 监测线程
  57. private static class View extends Thread {
  58. @Override
  59. public void run() {
  60. while (!Thread.interrupted()) {
  61. System.out.println("已经下载:" + count / 1024 + "KB");
  62. try {
  63. TimeUnit.SECONDS.sleep(1);
  64. } catch (InterruptedException e) {
  65. e.printStackTrace();
  66. }
  67. }
  68. }
  69. }
  70. public static void main(String[] args) throws IOException {
  71. URL url = new URL("http://down10.zol.com.cn/20180522/YunGameBoxSetup_dyg1167_yjwzgc.exe");
  72. URL url1 = new URL("http://download.skycn.com/hao123-soft-online-bcs/soft/P/2014-05-22_PowerWord.100.exe");
  73. URL url2 = new URL("http://xiazai.zol.com.cn/down.php?softid=428117&subcateid=1442&site=10&checkStr=28088c8250a5dcb30&pos=downloader_list&rand=4a6d84");
  74. downloader(url2);
  75. }
  76. }

文件断点续传

文件端点续传实现原理:

  • 如果响应头信息中存在“Accept-Ranges:bytes”属性,说明该网站支持断点续传
  • 就是在请求时可以通过设置请求头属性“Range:bytes=0-xx”指定服务器传输的位置

以上面获得的真实地址为例,构建 curl 请求:
image.png
从上面的响应头信息中可以看到:

  • 返回代码变成了 206 Partial Content
  • Content-Range 属性变成了 100-1000/33082232

多线程下载器