首页
文章
隐私
  • 繁體中文
  • 简体中文
首页
文章
隐私
  • 繁體中文
  • 简体中文

【开发笔记】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 标签(翻桌)。