southernMD 南山有壶酒
作词 : 偽物
分类
  • 暂无内容
站点信息
标签云
目录
作词 : 偽物
下载的哪些事
2023/8/15 14:34:59  |
0  |
27
jsfetchaxios
axios与fetch

我们现在有一个音频链接,现在我们可以对他进行一系列的下载操作

js 复制代码
const url = ref("http://m8.music.126.net/20230815153227/3b4da1f19a4b8c420ec03988ff1943bf/ymusic/39fa/a223/2a09/f4e6b984fd1a781bb2848e513de78d07.mp3")

音频链接在写稿时是可用的,如果你有自己的链接可以进行替换,一定要支持跨域访问

直接下载

点击下载按钮后会直接被浏览器接受和下载
fetch

js 复制代码
const d1 = ()=>{
    fetch(url.value)
    .then(response=>response.blob())
    .then((blob)=>{
        const downloadUrl = URL.createObjectURL(blob)
        const link = document.createElement('a')
        link!.href = downloadUrl
        link.download = Date.now() + '.mp3'; 
        link.textContent = 'Download';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(downloadUrl);
    })
}

axios

js 复制代码
const d1Axios = ()=>{
    axios.get(url.value, { responseType: 'blob' }) 
    .then(response => {
      const downloadUrl = URL.createObjectURL(response.data);
      const link = document.createElement('a');
      link.href = downloadUrl;
      link.download = Date.now() + '.mp3';
      link.textContent = 'Download';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(downloadUrl);
    })
}

带有显示进度的下载

fetch
对于fetch,我们必须手动监视下载的进程,通过response.body.getReader()返回一个流读取器,当首次接受到返回时ReadableStream构造函数会启动,调用reader去计算当前下载的数据量,在完成下载时关闭ReadableStream并将流返回给下一个promise,通过stream => new Response(stream)将流包装为一个 Response 对象

js 复制代码
const d2Fetch = () => {
    fetch(url.value)
    .then((response) => {
        loaded.value = 0
        totalBase.value = +(response.headers.get('content-length') ?? 0)
        const reader = response.body?.getReader() as ReadableStreamDefaultReader<Uint8Array>
        return new ReadableStream({
            start(controller) {
                function push() {
                    reader.read().then(({ done, value }) => {
                        if (done) {
                            controller.close()
                            return
                        }

                        loaded.value += value.byteLength
                        controller.enqueue(value)
                        push()
                    })
                }
                push()
            }
        })
    })
    .then(stream => new Response(stream))
    .then(response => response.blob())
    .then((blob)=>{
        const downloadUrl = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;
        link.download = Date.now() + '.mp3';
        link.textContent = 'Download';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(downloadUrl);
    })
}

axios
axios直接提供了onDownloadProgress事件,不需要去手动监视下载进度

js 复制代码
  axios.get(url.value, {
    responseType: 'blob',
    onDownloadProgress: progressEvent => {
      loaded.value = progressEvent.loaded;
      totalBase.value = progressEvent.total ?? 0;
    },
  })
    .then(response => {
      const blob = response.data;
      const downloadUrl = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = downloadUrl;
      link.download = Date.now() + '.mp3';
      link.textContent = 'Download';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(downloadUrl);
    })
    .catch(error => {
      console.error('Axios error:', error);
    });

可以暂停的下载

对于任何请求,一旦发起就不可能再次暂停,所有的暂停只是对请求的取消
fetch

js 复制代码
const abort = ref() as Ref<AbortController>
const d3Fetch = ()=>{
    abort.value = new AbortController()
    fetch(url.value,{
        signal:abort.value.signal
    })
        .then((response) => {
          ....
        })
        .then(stream => new Response(stream))
        .then(response => response.blob())
        .then((blob) => {
          ....
        })
}

AbortController是一个控制器对象,允许你根据需要中止web请求

js 复制代码
const stop = ()=>{
    abort.value.abort()
}

axios
方法是类似的只是名字的不同

js 复制代码
const CancelToken = axios.CancelToken;
const source = ref() as Ref<CancelTokenSource>
const d3Axios = ()=>{
    source.value = CancelToken.source();
    stopWay.value = 2
    axios.get(url.value, {
        responseType: 'blob',
        cancelToken: source.value.token,
        onDownloadProgress: progressEvent => {
            loaded2.value = progressEvent.loaded;
            totalBase2.value = progressEvent.total ?? 0;
        },
    })
    .then(response => {
        const blob = response.data;
        const downloadUrl = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;
        link.download = Date.now() + '.mp3';
        link.textContent = 'Download';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(downloadUrl);
    })
}
js 复制代码
const stop = ()=>{
    source.value.cancel() 
}

可以暂停以及继续的下载

fetch
对于fetch函数,由于response.body.getReader()的存在使得我可以监视到这个下载过程的数据传输,当我下载时我只需要将数据存储在chunks内,暂停下载时我,记录已经下载的字节数,在下次下载中设置Range请求头下载指定区间内数据,最后完成下载时对chunks内数据进行合并

js 复制代码
const abort2 = ref() as Ref<AbortController>
const loadedBase3 = ref(0)
const totalBase3 = ref(1)
let chunks: Uint8Array[] = []
const stopWay2 = ref(0)
const d4Fetch = ()=>{
    stopWay2.value = 1
    abort2.value = new AbortController()
    const Range = loadedBase3.value == 0 && totalBase3.value == 1 ? 
    `bytes=${loadedBase3.value}-` : 
    `bytes=${loadedBase3.value}-${totalBase3.value}`
    console.log(Range)
    fetch(url.value,{
        signal:abort2.value.signal,
        headers:{
            Range
        }
    })
        .then((response) => {
            loaded.value = 0
            totalBase3.value = +(response.headers.get('content-length') ?? 1) + loadedBase3.value
            const reader = response.body?.getReader() as ReadableStreamDefaultReader<Uint8Array>
            return new ReadableStream({
                start(controller) {
                    function push() {
                        reader.read().then(({ done, value }) => {
                            if (done) {
                                controller.close()
                                return
                            }

                            loadedBase3.value += value.byteLength
                            chunks.push(value)
                            controller.enqueue(value)
                            push()
                        }).catch((error)=>{
                            if (error.name === 'AbortError') {
                                console.log(`下载暂停,当前进度:
                                ${(loadedBase3.value / totalBase3.value * 100).toFixed(2) + '%' }
                                `,loadedBase3.value,totalBase3.value);
                                return null
                            } else {
                                return null
                            }
                        })
                    }
                    push()
                }
            })
        })
        .then(stream => new Response(stream))
        .then(response => response.blob())
        .then(() => {
            const newChunk = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0))
            let offset = 0;
            for (const chunk of chunks) {
                newChunk.set(chunk, offset);
                offset += chunk.byteLength;
            }
            const blob = new Blob([newChunk],{type:'audio/mp3'})
            const downloadUrl = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = downloadUrl;
            link.download = Date.now() + '.mp3';
            link.textContent = 'Download';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(downloadUrl);
        })
}

const stop2 = ()=>{
    abort2.value.abort()
}
const done = ()=>{
    d4Fetch()
}

对于axios,我没有找到合适的方法去保存已经下载过的数据,如果是上传数据可以通过服务器与客户端做切片上传的方式,通过校验切片记录文件上传的进度,等到所有的切片都上传完了将所有的切片合并。但是下载数据用axios我不知道怎么在取消时拿到已下载的数据,因此只能作罢。

标题:下载的哪些事

作者:southernMD

发布于:

评论
昵称
邮箱
网站
评论
0 / 125
评论列表(0)
移至左侧
回到顶部
日间模式
开启音乐
隐藏面板
a