【开发笔记】Node.js 处理 POST Body Data 的几个细节
最近处理 Exif 解析一个运用上的细节,后来的解决方案就是利用 POST Body 来传送 JavaScript 的 ArrayBuffer。本来以为是很直接的东西,没想到实作起来还是有些坑需要留意...
原生 HTTP 请求取数据
因为原生 HTTP POST 请求的 Body 本来就是 Buffer,所以搜集 Body 的 Data Chunk 本来是很直觉的做法。但是实作起来,发现 HTTP 请求的 end 事件并非总是触发。究其原因,发现原来在出请求附带的 Post Body 中,我只是发送整个 Data Buffer 最前端 128 KB 的部分。因此接收的服务端会一直闲置等待,直到 Gateway 超时,抛出 HTTP 504 状态码。虽然可以从检查 Body Data Buffer 的长度来判断结束的时间,但是假定本身不该是固定长度的数据显然不是个好主意。
let body = [];
req.on('data', (chunk) => {
// 或许可以检查 body 的长度来判断何时给予客户端 response
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// 如果数据完整传完的话,应该会触发 end 事件
});
采用 Node.js + Express.js 的 Middleware
采用 Express.js 框架的好处,就是可以透过 Middleware 来处理 Post Body。差别就是 middleware 处理过的请求,我们可以直接从 req.body 取得我们要的整段 Buffer。而非如前述原生 HTTP 请求的方式,自己监听 data 和 end 事件来拼接 Buffer。不过,因为笔者应用的数据解析比较特别,所以另自订了 Content-Type: application/exif.buffer
来跟其他的内容类型(如: application/json
)有个区隔。
// 可以在 root class 做个通用设置
const option = {
inflate: true,
limit: '100mb',
type: 'application/exif.buffer'
};
app.use(express.raw(option));
// 也可以在个别的路由下分别设置
const option = {
inflate: true,
limit: '100mb',
type: 'application/exif.buffer'
};
router.post('/lens/:Make',
express.raw(option),
async (req, res) => {
...
});
虽然同样是 413 状态码
其次就是 413 状态码抛出有两个地方。一个是 Node.js + Express.js 本身,HTTP 请求返回的显示是 413 Payload Too Large
。解决的方法参考前述,就是在 middleware 的设定将 limit 的限制放宽。另外就是 Nginx 也会抛出 413 状态码,这个时候显示的将会是 ERR_FAILED 413 Request Entity Too Large
。至于处理上,只要在 /etc/nginx/nginx.conf 加上 client_max_body_size
设置放宽容许量即可。
Byte Order 不一致
最后就是远端的档案,一开始是发现 Canon 家的档案会有部分 Exif 标签遗失,而 Nikon 家的不会。接着才找出是因为 FileReader 读取出来的 ArrayBuffer 和 fs 读取出来的 ArrayBuffer,转成 UInt8Array 后,竟然里面的 Byte Order 没有完全一样。后来比较起来,是 fs 的版本才能完整保留 Canon 家的 Exif 标签(翻桌)。