Sharp提取图片元数据报unsupported image format加Sleep恢复原因求解
问题根因
触发报错的核心原因
你监听了可读流(response.body)的end事件就提前返回了文件路径,此时文件还没有完全写入磁盘:
response.body的end事件仅代表上游HTTP响应的所有数据已经全部送入了写入流的缓存队列,不代表这些数据已经全部持久化到本地磁盘文件中- 不带复杂元数据的小图片缓存刷入磁盘速度极快,所以不会触发报错;但带XMP元数据的图片要么体积更大、要么元数据存储在文件尾部,你提前读取的时候文件内容不完整,sharp无法识别合法的图片格式标识,就会抛出
Input file contains unsupported image format错误 - 你添加的1秒睡眠刚好等完了写入流刷盘的全部流程,所以能正常运行,但这个方案不稳定,遇到大文件或者磁盘IO繁忙的场景还是会报错
你提到的fs.createWriteStream确实是同步方法,仅负责创建写入流对象,不需要await;但后续通过这个流写入数据的过程是完全异步的,你之前没等待写入完成就返回路径,才是问题的根源。
修复方案
把Promise的resolve逻辑绑定到写入流(fileStream)的finish事件上,同时补全写入流的错误监听即可,修改后的storeUrlToLocal函数如下:
async function storeUrlToLocal(sourceUrl) { const destPath = './'; const request = { method: 'GET', encoding: null, }; // 补充const声明,避免response成为全局变量 const response = await fetch(sourceUrl, request); if (response.status >= 400) throw new Error(`Failed to fetch data from ${sourceUrl}, status returned = ${response.status}`); const localPath = `${destPath}test.png`; const fileStream = fs.createWriteStream(localPath); return new Promise((resolve, reject) => { response.body.pipe(fileStream); // 监听可读流错误 response.body.on("error", reject); // 监听写入流错误 fileStream.on("error", reject); // 写入流全部数据刷入磁盘后再返回路径 fileStream.on("finish",() => { console.log('All writes are now complete.'); const fileExists = fs.existsSync(localPath); console.log(`File saved to ${localPath} = ${fileExists}`); resolve(localPath); }); }).catch(error => { console.log(error); // 捕获错误后重新抛出,避免上层函数拿到undefined throw error; }); }
可选优化方案
如果不需要持久化存储图片到本地,你可以直接读取响应的Buffer传给sharp,完全避免文件IO的异步问题,代码更简洁:
async function doStuff() { const imageUrl = '<INSERT_IMAGE_URL_HERE>'; const response = await fetch(imageUrl); if (response.status >= 400) { throw new Error(`Failed to fetch image, status: ${response.status}`); } const imageBuffer = await response.buffer(); const imageMetadata = await sharp(imageBuffer, { limitInputPixels: 5000000000 }).metadata(); console.log("ImageMetadata = ", imageMetadata); }
内容的提问来源于stack exchange,提问作者Codiegladney
相关产品推荐
相关产品推荐

