Package Exports
- bxf
- bxf/dist/bxf.umd.min.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (bxf) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
bxf(browser xhr and fetch)
bxf 是一款针对浏览器封装的多功能请求库,封装了 XHR 和 Fetch,以实现对 HTTP 请求的无缝处理。它能智能适应不同的环境,自动识别并支持各种请求类型。除了常规的网页请求外,它还特别设计以与使用 manifest_version: 3 的浏览器扩展无缝集成。这确保在现代 Web 开发环境中实现完美兼容性和最佳性能
安装
Use npm:
npm i bxf -S
Use yarn:
yarn add bxf
Use unpkg CDN:
<script src="https://unpkg.com/bxf"></script>
Examples
Use es6 module:
import bxf from 'bxf';
bxf('/url').then(res => console.log(res));
Use commonJs:
const bxf = require('bxf');
bxf('/url').then(res => console.log(res));
Use link:
<script src="https://unpkg.com/bxf"></script>
<script>
bxf('/url').then(res => console.log(res));
</script>
案例
/**
* 生成指定大小的文本文件
* @param {string} filename - 文件名
* @param {string} size - 文件大小,格式如 '1kb', '2mb', '3gb'
*/
function generateTextFile(filename, size, isDown = false) {
// 解析文件大小
const sizeRegex = /^(\d+)(kb|mb|gb)$/i;
const match = size.toLowerCase().match(sizeRegex);
if (!match) {
throw new Error('请使用正确的格式,如 "1kb", "2mb", "3gb"');
}
const amount = parseInt(match[1]);
const unit = match[2];
// 计算要生成的字节数
let bytes;
switch (unit) {
case 'kb':
bytes = amount * 1024;
break;
case 'mb':
bytes = amount * 1024 * 1024;
break;
case 'gb':
bytes = amount * 1024 * 1024 * 1024;
break;
default:
throw new Error('不支持的单位');
}
// 创建用于填充文件的内容
const filler = 'abcdefghijklmnopqrstuvwxyz0123456789';
let content = '';
// 生成内容(每次生成1MB,防止内存溢出)
const chunkSize = 1024 * 1024; // 1MB
let remainingBytes = bytes;
while (remainingBytes > 0) {
const currentChunkSize = Math.min(chunkSize, remainingBytes);
let chunk = '';
// 生成当前块的内容
while (chunk.length < currentChunkSize) {
const needed = currentChunkSize - chunk.length;
chunk += filler.repeat(Math.ceil(needed / filler.length)).slice(0, needed);
}
content += chunk;
remainingBytes -= currentChunkSize;
}
// 创建Blob对象
const blob = new Blob([content], { type: 'text/plain' });
if (isDown) {
// 创建下载链接并触发下载
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
// 清理
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 100);
}
return blob;
}
/**
* 获取表单
* @param {function} callback
* @returns
*/
function getFm(callback) {
const fm = new FormData();
fm.append('phone', '13812345678')
fm.append('pwd', '123456')
fm.append('__token__', Date.now())
if (typeof callback == 'function') {
callback.call(fm, fm);
}
return fm;
}
// 测试函数
async function bxfTest(url, engine = 'fetch', toDataOnly = false) {
let idx = 0;
const resultProxy = new Proxy({}, {
get: function (target, proKey, receiver) {
if (proKey == '__RAW') {
return target;
}
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
if (!Object.hasOwn(target, propKey)) {
idx++;
}
return Reflect.set(target, propKey, value, receiver)
}
})
// get请求
resultProxy[idx + '.get配置请求'] = await bxf({
url,
params: {
idx,
page: 1,
page_num: 100,
},
engine,
toDataOnly
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.get快捷请求'] = await bxf.get(url, {
params: {
idx,
page: 1,
page_num: 100,
},
engine,
toDataOnly
}).catch(err => {
return ['error', err];
})
// 手动中断
await new Promise(async resolve => {
let signal = bxf.CancelToken();
let temp = bxf.get(url, {
params: {
idx,
sleep: 10,
},
engine,
toDataOnly,
signal,
}).catch(err => {
return ['error', err];
})
setTimeout(function () {
signal();
}, 3000)
await temp.then(res => {
resultProxy[idx + '.手动中断请求'] = res
}).finally(resolve)
})
resultProxy[idx + '.请求超时'] = await bxf.get(url, {
params: {
idx,
sleep: 10,
},
engine,
toDataOnly,
timeout: 5000,
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.get请求无params自动处理data'] = await bxf({
url: (function () {
let _url = new URL(url, location);
_url.searchParams.append('idx', idx);
return _url.toString();
})(),
engine,
toDataOnly,
data: {
page: 1
},
})
resultProxy[idx + '.get请求无params自动处理data-忽略非普通对象'] = await bxf({
url: (function () {
let _url = new URL(url, location);
_url.searchParams.append('idx', idx);
return _url.toString();
})(),
engine,
toDataOnly,
data: getFm(),
})
resultProxy[idx + '.post请求'] = await bxf.post(url, {
'title': '文章标题',
'categoryId': 1,
'content': `<div>hello world</div>`,
'uid': 123,
}, {
params: {
idx,
engine
},
engine,
toDataOnly,
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.post 指定响应类型blobText'] = await bxf.post({
url,
data: {
'title': '文章标题',
'categoryId': 1,
'content': `<div>hello world</div>`,
'uid': 123,
},
params: {
idx,
engine,
responseType: 'blobText'
},
engine,
toDataOnly,
responseType: 'blobText'
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.post 指定响应类型document'] = await bxf.post({
url,
data: {
'title': '文章标题',
'categoryId': 1,
'content': `<div>hello world</div>`,
'uid': 123,
},
params: {
idx,
engine,
responseType: 'document'
},
engine,
toDataOnly,
responseType: 'document'
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.post 指定响应类型为blob'] = await bxf.post({
url,
data: {
'title': '文章标题',
'categoryId': 1,
'content': `<div>hello world</div>`,
'uid': 123,
},
params: {
idx,
type: 'fetch',
responseType: 'blob'
},
engine,
toDataOnly,
responseType: 'blob'
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.post 指定请求类型query'] = await bxf.post({
url,
data: {
'title': '文章标题',
'categoryId': 1,
'content': `<div>hello world</div>`,
'uid': 123,
},
params: {
idx,
engine,
requestType: 'query'
},
engine,
toDataOnly,
requestType: 'query'
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.post 表单文件上传'] = await bxf({
url,
method: 'post',
params: {
idx,
engine: 'xhr',
requestType: 'formData'
},
engine,
toDataOnly,
data: getFm(function () {
let fileName = 'myText.txt';
this.append('file', generateTextFile(fileName, '1mb'), fileName);
}),
xhr(xhr, config) {
console.info('测试上传进度,请将网络调至慢速4G');
xhr.upload.onprogress = function (eve) {
if (eve.lengthComputable) {
console.log('当前进度', eve.loaded / eve.total);
}
}
}
}).catch(err => {
return ['error', err];
})
// 其他方法测试
resultProxy[idx + '.delete'] = await bxf.delete(url, {
engine,
toDataOnly,
params: {
idx,
engine,
method: 'delete',
},
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.head'] = await bxf.head(url, {
engine,
toDataOnly,
params: {
idx,
engine,
method: 'head',
},
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.options'] = await bxf.options(url, {
engine,
toDataOnly,
params: {
idx,
engine,
method: 'options',
},
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.put'] = await bxf.put(url, {
id: 1
}, {
engine,
toDataOnly,
params: {
idx,
engine,
method: 'put',
},
}).catch(err => {
return ['error', err];
})
resultProxy[idx + '.patch'] = await bxf.patch(url, {
id: 1
}, {
engine,
toDataOnly,
params: {
idx,
engine,
method: 'patch',
},
}).catch(err => {
return ['error', err];
})
return resultProxy.__RAW;
}
async function testMain() {
console.log('开始xhr请求测试')
await bxfTest('/index/api', 'xhr', false).then(result => console.log('xhr', result))
console.log('开始fetch请求测试')
bxfTest('/index/api', 'fetch', false).then(result => console.log('fetch', result))
}
版本升级备注
1.1.2-beta
- 1.1.*是在1.0.*的基础上参考redaxios封装,变动有点大,但整体更加简洁合理,使用方法和版本差异,暂时请先参考案例使用,更详细的文档后续发布正式版再完善