Skip to content

Latest commit

 

History

History
274 lines (195 loc) · 8.86 KB

README.zh-hans.md

File metadata and controls

274 lines (195 loc) · 8.86 KB

axios-multi-down

Axios 插件,通过 Range 特性, 将 大文件 分割,并发多个 Axios 请求加快大文件下载速度。

中文 | English

Demo

https://lqzhgood.github.io/axios-multi-down

安装

npm i axios-multi-down
<script src="https://unpkg.com/axios-multi-down/lib/AxiosMultiDown.umd.js"></script>

使用

import axiosBase from 'axios';
import AxiosMultiDown from 'axios-multi-down';

const axios = axiosBase.create({});

AxiosMultiDown(axios);

axios
    .down('http://example.com/test')
    .then(result => {})
    .catch(err => {});

axios
    .down('http://example.com/test', {
        method: 'get',
        headers: { 'X-Requested-With': 'XMLHttpRequest' },
        // ...AxiosRequestConfig
    })
    .then(result => {})
    .catch(err => {});

axios
    .down({
        url: 'http://example.com/test',
        method: 'post',
        data: {
            firstName: 'Fred',
        },
        // ...AxiosRequestConfig
    })
    .then(result => {})
    .catch(err => {});

Api

AxiosMultiDown

AxiosMultiDown( axios )
AxiosMultiDown( axios [ , DownConfig ] ) // Global DownConfig
AxiosMultiDown.EventEmitter

/src/event.ts

new 一个事件实例,Api

AxiosMultiDown.RetryQueue

手动重试失败队列,一般配合 onFinishErr 使用

AxiosMultiDown.RetryQueue(errQueue: IBlockData[], config: IDownConfig): void;

RetryQueue 会重试实例上失败的所有 Block , 而不是 errQueue 中的 BlockerrQueue 仅代表会优先执行的 Block

// e.g

await axios.down( url , {
        maxRetries: 10,
        errMode: AxiosMultiDown.const.ERROR_MODE.WAIT
        onFinishErr(errorQueue, queue, downConfig) {
            // errorQueue 中包含这个实例的所有失败 Block

            // 如果不考虑网络波动,每个 block 返回时间一致
            // errorQueue = [ b1, b2, b3, b4, b5, b6, b7, b8]
            // downConfig = { max:2 }

            AxiosMultiDown.RetryQueue([b3,b4,b5,b6], downConfig);
            // 那么 RetryQueue 的重试顺序结果将会是 [b3,b4, b5,b6,  b1,b2,b7,b8]
        },
    },
);
AxiosMultiDown.const.TEST_METHOD

DownConfig.testMethod = AxiosMultiDown.const.TEST_METHOD

Name Description
HEAD
SELF
AxiosMultiDown.const.ERROR_MODE

DownConfig.errMode = AxiosMultiDown.const.ERROR_MODE

Name Description
RETURN 立即返回错误,下载中止
WAIT 等待手动处理,可和 onFinishErr 配合手动重试

axios.down

axios.down( url )
axios.down( AxiosRequestConfig )

axios.down( url, AxiosRequestConfig )
axios.down( AxiosRequestConfig , DownConfig )

axios.down( url , AxiosRequestConfig, DownConfig )
DownConfig

defaultDownConfig => /src/const.ts

Name Type Default Description remark
max Number 3 最大同时进行下载的数量 *1
blockSize Number K B G T 10M 单个下载的块大小 单位 byte
testMethod TEST_METHOD TEST_METHOD.HEAD 用于探测服务器是否支持 Range 的HTTP方法, self 代表使用 AxiosRequestConfig.method *2 如果使用 self, 请注意 幂等性
maxRetries Number 3 block 下载错误,最大重试次数 重试将会在所有 block 下载完后进行
retryInterval Number 1000 block 下载错误,重试间隔 单位 ms
errMode ERROR_MODE ERROR_MODE.RETURN 当所有block部分下载失败时的处理方式 *3 如果设置为 WAIT,可通过 onFinishErr 手动重试
$Hook Function - Event 类似,如 on('data',fn) -> onData(fn), onceData(fn) Hook 是同步的, Event 是异步的
*1
    > max 会被改写,规则如下

    blockLength = Math.ceil( contentLength / blockSize );
    max = max <= blockLength ? max : blockLength;

    如  contentLength = 10 , max = 5, blockSize = 9;
    max 会被改写为 2 -> [ 0-8 , 9-9 ]

*2
    浏览器环境将强制使用 HEAD 方法,因为当前不支持 responseType === 'steam'

*3
    let retry = 0
    const resp = await axios.down( url , {
            maxRetries: 10,
            errMode: AxiosMultiDown.const.ERROR_MODE.WAIT // 重点
            onFinishErr(errorQueue, queue, downConfig) {
                // 这将下载所有Block,且每个Block都重试10次以后,手动再重试3次
                while( retry++ < 3){
                    AxiosMultiDown.RetryQueue(eQ, downConfig);
                }
            },
        },
    );

    // 如果成功,将得到 resp, 如果下载失败,将永远不会到这里
    console.log(resp);
IBlockData
interface IBlockData {
    s: number; // block start position
    e: number; // block end position
    i: number; // block index
    resp?: AxiosResponse;
        resp.data: Uint8Array; // block data, in multi down, type is Uint8Array
}
IAxiosDownResponse

axios.down(url).then(( resp: IAxiosDownResponse extends AxiosResponse )=>{})

resp = {
    ...axiosResponse,
    isMulti: boolean; // Is it downloaded through multiple requests?
    queue: IBlockData[];
    downConfig: IDownConfig;
}

...axiosResponse 部分将被覆写两次

  • 第一次完成 axios 请求.
  • 最后一次完成 axios 请求,
    • 其他修改
      • resp.status = 200;
      • resp.statusText = 'OK';
      • resp.headers['content-type'] = totalContentLength;

事件

const emitter = new AxiosMultiDown.EventEmitter();

emitter.on('preDown', (queue: IBlockData[], config: IDownConfig) => void)
emitter.on('data', (block: IBlockData, queue: IBlockData[], config: IDownConfig) => void)
emitter.on('blockError', (block: IBlockData, queue: IBlockData[], config: IDownConfig) => void)
emitter.on('end', (queue: IBlockData[], config: IDownConfig) => void)
emitter.on('finishErr', (errQueue: IBlockData[], queue: IBlockData[], config: IDownConfig) => void)

axios.down( '/test', {} , { emitter } )

emitter.onceemitter.on 参数相同,但仅执行一次

注意事项

不支持 Range

如果资源不支持 Range,将自动回退使 axios.down === axios 并返回结果

跨域 CORS

如果你访问一个跨域的服务器,需要服务器在 Access-Control-Expose-Headers 中包含 Content-Range,否则客户端获取的 headers 中不包含 Content-Range

docs: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

res.setHeader('Access-Control-Expose-Headers', '$OtherHeaders, Content-Range');

测试

npm run test

TODO

  • responseType 使用 steam 获取更好的性能
    • 需要 axios 使用 fetch 作为 adapter 才可让浏览器支持