有时候,所见并不是所得,有些包,你需要去翻他的源码才知道为什么会这样。
背景
今天调试一个程序,用到了一个很久之前的NPM包,名为formstream,用来将form表单数据转换为流的形式进行接口调用时的数据传递。
这是一个几年前的项目,所以使用的是Generator+co实现的异步流程。
其中有这样一个功能,从某处获取一些图片URL,并将URL以及一些其他的常规参数组装到一起,调用另外的一个服务,将数据发送过去。
大致是这样的代码:
const co = require('co') const moment = require('moment') const urllib = require('urllib') const Formstream = require('formstream') function * main () { const imageUrlList = [ 'img1', 'img2', 'img3', ] // 实例化 form 表单对象 const form = new Formstream() // 常规参数 form.field('timestamp', moment().unix()) // 将图片 URL 拼接到 form 表单中 imageUrlList.forEach(imgUrl => { form.field('image', imgUrl) }) const options = { method: 'POST', // 生成对应的 headers 参数 headers: form.headers(), // 告诉 urllib,我们通过流的方式进行传递数据,并指定流对象 stream: form } // 发送请求 const result = yield urllib.request(url, options) // 输出结果 console.log(result) } co(main)也算是一个比较清晰的逻辑,这样的代码也正常运行了一段时间。
如果没有什么意外,这段代码可能还会在这里安静的躺很多年。
但是,现实总是残酷的,因为一些不可抗拒因素,必须要去调整这个逻辑。
之前调用接口传递的是图片URL地址,现在要改为直接上传二进制数据。
所以需求很简单,就是将之前的URL下载,拿到buffer,然后将buffer传到formstream实例中即可。
大致是这样的操作:
- imageUrlList.forEach(imgUrl => { - form.field('image', imgUrl) - }) + let imageUrlResults = yield Promise.all(imageUrlList.map(imgUrl => + urllib.request(url) + )) + + imageUrlResults = imageUrlResults.filter(img => img && img.status === 200).map(img => img.data) + + imageUrlResults.forEach(imgBuffer => { + form.buffer('image', imgBuffer) + })下载图片 -> 过滤空数据 -> 拼接到form中去,代码看起来毫无问题。
不过在执行的时候,却出现了一个令人头大的问题。
最终调用yield urllib.request(url, options)的时候,提示接口超时了,起初还以为是网络问题,于是多执行了几次,发现还是这样,开始意识到,应该是刚才的代码改动引发的bug。
