分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

【HTML】Http分段下载详解

发布时间:2023-09-06 01:21责任编辑:沈小雨关键词:HTML

一.为什么需要Http分段下载  

 在实际的业务开发中,大文件使用Http普通下载非常容易OOM(内存溢出)或是链接超时的错误,这种情况下应该就应该考虑使用Http的分段下载了。下面笔者为你介绍,Http协议如何实现分段下载。

二.Http协议的结构介绍

    在正式开始之前,这里笔者先介绍一下Http的报文结构。Http的报文结构是由状态行、头部、空行、主体组成。在这里读者需要注意,GET请求和POST得到的报文结构是不一样的,GET请求无请求数据,而POST请求有请求数据。关于Http的详细信息,读者可以参考Http协议详解,而我们接下来讨论的Range就是请求头部中的一个字段。
三.Http协议的头部Range介绍
    Range字段是Http1.1开始新增加的,Http1.1和传统的Http1.0相比,最大的特点就是解决1.0中不能支持多请求的缺点。判断一个WEB服务器是否支持分段下载可以通过查看 返回头是否有Accept-Ranges:Byte 字段。分段下载分为两种,一种就是一次请求一个字段,一种就是一次请求多个字段。关于超文本传输的报文信息,读者可以通过filter、burp或是浏览器的控制台中查看报文的信息。
 

   (一)一次请求一个分段

    下面看一下Range字段常用表示的写法:
    Range: bytes=0-1024 获取最前面1025个字节
    Range: bytes=-500   获取最后500个字节
    Range: bytes=1025-  获取从1025开始到文件末尾所有的字节
    Range: 0-0          获取第一个字节
    Range: -1           获取最后一个字节
    例如,在一个请求头中有Range:byte=0-1024,那么表示的意思就是请求数据的前1025个字节。
     如果这个分段请求的返回码是206,并且指示的分段范围是0-1024,文件的总大小是7877,那么在响应头中的数据应该表示为:
    Content-Range: bytes 0-1024/7877

    (二)一次请求多个分段

    多个分段和单个分段相差无几,只需要在请求头的分段中添加多个分段区域就可以了。
    例如:在请求头出现Range:byte:0-1024,2000-3000,表示的含义就是请求前1025个字节信息,和从2000到3000字节的信息。
    如果分段请求的返回状态码是206,那么Content-Range的返回值和一次请求单个分段一样。


四.使用Java实现文件分段下载

    接下来笔者结合Java实现一个多线程分段下载的功能。使用Java多线程实现实现这个功能的大致思想,使用多个线程负责文件的子模块的下载,每个线程都要记录好下载的结束位置,以便于作为下个线程下载的开始位置。直接上代码:

多线程的下载类:

import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import java.util.concurrent.CountDownLatch;public class MutiThreadDownLoad { ???/** ????* 同时下载的线程数 ????*/ ???private int threadCount; ???/** ????* 服务器请求路径 ????*/ ???private String serverPath; ???/** ????* 本地路径 ????*/ ???private String localPath; ???/** ????* 线程计数同步辅助 ????*/ ???private CountDownLatch latch; ????public MutiThreadDownLoad(int threadCount, String serverPath, String localPath, CountDownLatch latch) { ???????this.threadCount = threadCount; ???????this.serverPath = serverPath; ???????this.localPath = localPath; ???????this.latch = latch; ???} ????public void executeDownLoad() { ????????try { ???????????URL url = new URL(serverPath); ???????????HttpURLConnection conn = (HttpURLConnection) url.openConnection(); ???????????conn.setConnectTimeout(5000);//设置超时时间 ???????????conn.setRequestMethod("GET");//设置请求方式 ???????????int code = conn.getResponseCode(); ???????????if (code == 200) { ???????????????//服务器返回的数据的长度,实际上就是文件的长度,单位是字节 ???????????????int length = conn.getContentLength(); ???????????????System.out.println("文件总长度:" + length + "字节(B)"); ???????????????RandomAccessFile raf = new RandomAccessFile(localPath, "rwd"); ???????????????//指定创建的文件的长度 ???????????????raf.setLength(length); ???????????????raf.close(); ???????????????//分割文件 ???????????????int blockSize = length / threadCount; ???????????????for (int threadId = 1; threadId <= threadCount; threadId++) { ???????????????????//第一个线程下载的开始位置 ???????????????????int startIndex = (threadId - 1) * blockSize; ???????????????????int endIndex = startIndex + blockSize - 1; ???????????????????if (threadId == threadCount) { ???????????????????????//最后一个线程下载的长度稍微长一点 ???????????????????????endIndex = length; ???????????????????} ???????????????????System.out.println("线程" + threadId + "下载:" + startIndex + "字节~" + endIndex + "字节"); ???????????????????new DownLoadThread(threadId, startIndex, endIndex).start(); ???????????????} ????????????} ????????} catch (Exception e) { ???????????e.printStackTrace(); ???????} ?????} ?????/** ????* 内部类用于实现下载 ????*/ ???public class DownLoadThread extends Thread { ???????/** ????????* 线程ID ????????*/ ???????private int threadId; ???????/** ????????* 下载起始位置 ????????*/ ???????private int startIndex; ???????/** ????????* 下载结束位置 ????????*/ ???????private int endIndex; ????????public DownLoadThread(int threadId, int startIndex, int endIndex) { ???????????this.threadId = threadId; ???????????this.startIndex = startIndex; ???????????this.endIndex = endIndex; ???????} ?????????@Override ???????public void run() { ????????????try { ???????????????System.out.println("线程" + threadId + "正在下载..."); ???????????????URL url = new URL(serverPath); ???????????????HttpURLConnection conn = (HttpURLConnection) url.openConnection(); ???????????????conn.setRequestMethod("GET"); ???????????????//请求服务器下载部分的文件的指定位置 ???????????????conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); ???????????????conn.setConnectTimeout(5000); ???????????????int code = conn.getResponseCode(); ????????????????System.out.println("线程" + threadId + "请求返回code=" + code); ????????????????InputStream is = conn.getInputStream();//返回资源 ???????????????RandomAccessFile raf = new RandomAccessFile(localPath, "rwd"); ???????????????//随机写文件的时候从哪个位置开始写 ???????????????raf.seek(startIndex);//定位文件 ????????????????int len = 0; ???????????????byte[] buffer = new byte[1024]; ???????????????while ((len = is.read(buffer)) != -1) { ???????????????????raf.write(buffer, 0, len); ???????????????} ???????????????is.close(); ???????????????raf.close(); ???????????????System.out.println("线程" + threadId + "下载完毕"); ???????????????//计数值减一 ???????????????latch.countDown(); ????????????} catch (Exception e) { ???????????????e.printStackTrace(); ???????????} ????????} ???}}
MutiThreadDownLoad

接下来是测试文件:

import java.util.concurrent.CountDownLatch;public class ClientTest{ ???public static void main(String[] args) { ????????int threadSize = 4; ???????String serverPath = "https://www.baidu.com"; ???????String localPath = "NewsReader.apk"; ???????CountDownLatch latch = new CountDownLatch(threadSize); ???????MutiThreadDownLoad m = new MutiThreadDownLoad(threadSize, serverPath, localPath, latch); ???????long startTime = System.currentTimeMillis(); ???????try { ???????????m.executeDownLoad(); ???????????latch.await();//等待所有的线程执行完毕 ???????} catch (InterruptedException e) { ???????????e.printStackTrace(); ???????} ???????long endTime = System.currentTimeMillis(); ???????System.out.println("全部下载结束,共耗时" + (endTime - startTime) / 1000 + "s"); ???}}
ClientTest

【HTML】Http分段下载详解

原文地址:http://www.cnblogs.com/HDK2016/p/7760079.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved