透传数据及文件
背景:
调用后台接口之前,需要按照约定统一规格化数据以及用户鉴权验证,因此管理端辅助开发代理接口,透传数据及文件给对应后台接口进行处理。
可能存在问题的点:
1、文件透传(是否可直接传递文件流?不方便处理采取何种方案?)
解决方案:
经沟通及验证,后台有严格的接收数据字符格式限制,暂定以bodyData的对象字符方式传送数据;因此文件传送需要一种变形方式,为保证不乱码,将获取到的文件buffer转为base64字符串,后台获取之后再生成对应文件。(不采取utf-8编码,因为其为3个字节表示,容易产生乱码;base64编码永远是4的倍速)
实现:
// 基于egg.js 处理文件的过程
async parseFileBase64(data, files) {
const fileParseArr = (data._parseFileBase64 || '').split('|');
if (files.length) {
const eachFileMap = new Map();
for (let j = 0; j < files.length; j++) {
if (eachFileMap.has(files[j].field)) {
eachFileMap.set(files[j].field, eachFileMap.get(files[j].field).concat([ files[j] ]));
} else {
eachFileMap.set(files[j].field, [ files[j] ]);
}
}
for (const [ keys, values ] of eachFileMap) {
if (fileParseArr.indexOf(keys.slice(0, -2)) !== -1) {
if (values.length > 1) {
for (let i = 0; i < values.length; i++) {
data[keys.slice(0, -2) + '_' + i] = await fs.readFileSync(values[i].filepath).toString('base64');
}
} else if (values.length === 1) {
data[keys.slice(0, -2)] = await fs.readFileSync(values[0].filepath).toString('base64');
}
}
}
} else {
// 未上传则将文件属性名去除
for (let i = 0; i < fileParseArr.length; i++) {
delete data[fileParseArr[i]];
}
}
return data;
},
其他探究:
了解了下拿到文件之后透传文件,可借助辅助包:
// 常用上传
const req = urllib.request(buyUrl, {
keepHeaderCase: true,
headers: {
'F-AUTH-APPID': 'F-AUTH-APPID', // 无关
},
files: {
publicUploadFile: fs.createReadStream(ctx.request.files[0].filepath),
},
dataType: 'text',
type: 'POST',
data: bodyData,
}, function(err, data, res) {
console.log('err, data, res ---> ', err, data, res);
});
// 选项: options.stream
const form = formstream();
form.file('publicUploadFile', ctx.request.files[0].filepath);
form.field('hello', '你好urllib');
const req = urllib.request(buyUrl, {
method: 'POST',
headers: form.headers(),
stream: form,
}, function(err, data, res) {
//data buffer格式
console.log('err, data, res ---> ', err, data, res);
});
console.log('req ---> ', req);
注意:
Base64 编码将三个八位字节转换为四个编码字符,转码之后,文件字节数会增大1/3,因此需要合理估算大小;
拓展:
1、管理端文件上传:
js下,file基于Blob(可理解为web的二进制文件)实现的一个增加了关于文件有关信息的类;
上传方式:
1、form表单(点击其中的submit按钮,上传会刷新页面)
2、ajax + formdata(异步上传 + 局部更新页面,常用)
FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send() 方法发送出去,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 “multipart/form-data”,它会使用和表单一样的格式。
2、nodejs的buffer、stream、binary
详细解释
在缓冲区buffer中,我们可以操作正在流stream式传输的二进制数据binay或与之交互。
(buffer站台、stream巴士、binary乘客、一辆巴士的乘客chunk)
buffer存储在内存当中,大小有限,由C++层分配,不在V8中。stream操作期间会自动创建一个对应buffer,初次之外可创建自己的buffer进行数据交互。
// buffer常用方法
.toJSON() method presents the data as the Unicode Code Points of the characters
// { type: 'Buffer', data: [ 104, 101, 108, 108, 111, 32, 98, 117, 102, 102, 101, 114 ]}
.length
.write("Buffer really rocks!")