我在工作过程中用到了request模块来模拟前端请求进行接口测试,但是在测试buffer的时候遇到了问题,卡了很久,查阅了大量的资料才发现是个由底层逻辑触发的乌龙。因此记录下来并分享给各位。
首先引入request模块(假设你已有NodeJS):
npm install -s request
同时你需要一个后端,可以使用express-generator生成,参考https://blog.csdn.net/Z_ammo/article/details/103559758
设置接口:
app = express();
app.post('/', function(req, res, next) {
console.log(req.headers);
let buf = [];
req.on('data', (data) => {
buf.push(data);
});
req.on('end', () => {
buf = Buffer.concat(buf);
console.log(buf.toString());
});
res.send('1');
});
现在发送请求:
var formData = {
my_field: 'my_value',
my_buffer: Buffer.from([1,2,3]) // 这里我使用了request官方的示例,也就是坑爹的开始
};
//post请求
request.post({
url: "http://127.0.0.1:8080/",
headers: {
"content-type": "multipart/form-data",
},
formData: formData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
});
好的,那么我们来看看后端收到的请求吧:
{
'content-type': 'multipart/form-data; boundary=--------------------------536170949929771112772934',
host: '127.0.0.1:3000',
'content-length': '322',
connection: 'close'
}
POST / 200 10.093 ms - 1
----------------------------536170949929771112772934
Content-Disposition: form-data; name="my_field"
my_value
----------------------------536170949929771112772934
Content-Disposition: form-data; name="my_buffer"
Content-Type: application/octet-stream
----------------------------536170949929771112772934--
结果是:字符串很正常的收到了,但是Buffer对象却没有显示出来(实际上显示了三个方框,也就是乱码)。
我以为是Buffer自动分块的问题,但是即便采用了Buffer拼接也无济于事,更何况这里使用的是ASCII码,没有分块问题。
我还怀疑是编码问题,但是不论怎么修改编码方式,结果都是乱码,不得已,只能从二进制数据入手了。
打印JSON.stringify()
console.log(JSON.stringify(buf));
结果如下:
{"type":"Buffer","data":[45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,51,49,49,50,55,56,57,53,54,56,57,55,50,49,49,52,57,53,50,53,56,51,55,48,13,10,67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105,111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110,97,109,101,61,34,109,121,95,102,105,101,108,100,34,13,10,13,10,109,121,95,118,97,108,117,101,13,10,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,51,49,49,50,55,56,57,53,54,56,57,55,50,49,49,52,57,53,50,53,56,51,55,48,13,10,67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105,111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110,97,109,101,61,34,109,121,95,98,117,102,102,101,114,34,13,10,67,111,110,116,101,110,116,45,84,121,112,101,58,32,97,112,112,108,105,99,97,116,105,111,110,47,111,99,116,101,116,45,115,116,114,101,97,109,13,10,13,10,1,2,3,13,10,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,51,49,49,50,55,56,57,53,54,56,57,55,50,49,49,52,57,53,50,53,56,51,55,48,45,45,13,10]}
首先我们看到,数字中存在大量的'45'区间,很明显这就是我们的'--------------'分割符,因此可以确定大致区域。经过处理,我找到乱码的区域如下:
13,10,13,10,1,2,3,13,10
现在我们验证一下:
45:- 13:回车 10:换行 1:标题开始 2:正文开始 3:正文结束
所以Buffer的内容可以解释为:
“回车”“换行”“回车”“换行”“标题,文件正文,正文结束”“回车”“换行”
所以这个Buffer实际上是传递了一个空的文档!因为全是“无法描述”的字符,所以是乱码。
那么文件的主体在哪里呢?我的数组呢?
我查看了request的官方文档:https://www.npmjs.com/package/request
发现原来request的form-data处理是引用了外部的模块:https://github.com/form-data/form-data
来看看官方的示例:
var form = new FormData();
form.append( 'my_buffer', Buffer.from([0x4a,0x42,0x20,0x52,0x6f,0x63,0x6b,0x73]) );
form.append( 'my_file', fs.readFileSync('/foo/bar.jpg') );
axios.post( 'https://example.com/path/to/api',
form.getBuffer(),
form.getHeaders()
)
官方也是简单地将数组转换成Buffer,而且没有乱码。
这里我才意识到,官方发送的是16进制数字,而我使用的示例发送的是1,2,3。
突然想起来,Buffer会将数组的内容转换为对应的编码,然后依次连接!
也就是说,“13,10,13,10,1,2,3,13,10”中的“1,2,3”实际上就是我们传递的数组参数,而不是什么文件内容!
我晕……
我是按照request官方文档的示例,使用了'[1,2,3]'的数组……
request官方文档使用的样例也太随意了……
另,form-data模块官方文档提示:不要直接传递Array对象,直接传递Array对象会自动拆分其内容,并分成多个数据块传递。