Lambda中Sharp处理图片报错:Input buffer contains unsupported image format
我已经在lovell/sharp的issues板块提交了这个问题,不过还是希望能从社区得到更多相关建议。
我的场景是:一个由SQS触发的Lambda函数,通过图片URL获取源图片后,尝试用Sharp进行处理,但每次运行都会抛出格式不支持的错误。
核心代码片段
import axios from "axios"; import sharp from "sharp"; let sourceImageBuffer, imageBuffer, imageMetadata, problemWithImage; // 获取源图片 try { const source = ( await axios({ url: rawImage.sourceUrl, responseType: "arraybuffer" }) ).data; sourceImageBuffer = Buffer.from(source); console.log("sourceImageBuffer", sourceImageBuffer); } catch (error) { problemWithImage = "can't access source image"; console.log("getObject can't access source image", error); } // 转换为Sharp对象处理 try { if (!!sourceImageBuffer) { imageBuffer = await sharp(sourceImageBuffer).toBuffer(); imageMetadata = await sharp(imageBuffer).metadata(); } } catch (error) { console.log( "can't process source image. is it an image? error ", error ); problemWithImage = "can't process source image. is it an image?"; throw new Error(error); }
报错信息
2020-09-29T09:05:07.436Z 2d64036b-3a05-474f-a22a-93e3446204d6 INFO can't process source image. is it an image? error [Error: Input buffer contains unsupported image format]
已做的排查工作
- 试过用
s3.getObject或其他请求库获取图片,结果完全一致 - 打印的
sourceImageBuffer开头是<Buffer ff d8 ff e0 ...>,符合JPEG文件的标识,看起来是正常的 - 在本地Mac环境(非Docker)运行代码完全正常,没有任何报错
- 花了5天时间排查,查阅了大量资料,但仍然找不到问题根源
当前环境信息
Sharp依赖的系统库版本
{ "cairo": "1.16.0", "exif": "0.6.22", "expat": "2.2.9", "ffi": "3.3", "fontconfig": "2.13.92", "freetype": "2.10.2", "fribidi": "1.0.10", "gdkpixbuf": "2.40.0", "gettext": "0.21", "gif": "5.1.4", "glib": "2.65.2", "gsf": "1.14.47", "harfbuzz": "2.7.1", "jpeg": "2.0.5", "lcms": "2.11", "orc": "0.4.31", "pango": "1.46.1", "pixman": "0.40.0", "png": "1.6.37", "svg": "2.49.4", "spng": "0.6.0", "tiff": "4.1.0", "vips": "8.10.0", "webp": "1.1.0", "xml": "2.9.10", "zlib": "1.2.11" }
Sharp支持的图片格式
{ "jpeg": { "id": "jpeg", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": true, "buffer": true, "stream": true } }, "png": { "id": "png", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": true, "buffer": true, "stream": true } }, "webp": { "id": "webp", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": true, "buffer": true, "stream": true } }, "tiff": { "id": "tiff", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": true, "buffer": true, "stream": true } }, "magick": { "id": "magick", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "openslide": { "id": "openslide", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "dz": { "id": "dz", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": true, "buffer": true, "stream": true } }, "ppm": { "id": "ppm", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "fits": { "id": "fits", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "gif": { "id": "gif", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": false, "buffer": false, "stream": false } }, "svg": { "id": "svg", "input": { "file": true, "buffer": true, "stream": true }, "output": { "file": false, "buffer": false, "stream": false } }, "heif": { "id": "heif", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "pdf": { "id": "pdf", "input": { "file": false, "buffer": false, "stream": false }, "output": { "file": false, "buffer": false, "stream": false } }, "vips": { "id": "vips", "input": { "file": true, "buffer": false, "stream": false }, "output": { "file": true, "buffer": false, "stream": false } }, "raw": { "id": "raw", "input": { "file": false, "buffer": true, "stream": true }, "output": { "file": false, "buffer": true, "stream": true } } }
package.json中的Sharp版本
"sharp": "^0.26.1"
我的建议
结合你的场景和排查情况,我觉得可以从这几个方向尝试解决:
重点检查Sharp的跨环境兼容性
Sharp是依赖系统原生库的模块,本地Mac环境安装的二进制包和Lambda的Linux环境不兼容是这类问题的常见原因。你可以:- 用Docker模拟Lambda的Linux环境(比如
amazonlinux:2镜像)来安装依赖并打包代码,确保部署的是针对Linux编译的Sharp版本; - 直接使用官方提供的Sharp Lambda层,这样能确保依赖的系统库和Lambda环境完全匹配,避免手动编译的问题。
- 用Docker模拟Lambda的Linux环境(比如
尝试用Stream替代Buffer处理
当前代码是把响应转成arraybuffer再转成Buffer,中间可能存在隐性的转换问题。可以直接用axios的stream响应类型,传给Sharp的stream接口,跳过Buffer转换步骤:
const response = await axios({ url: rawImage.sourceUrl, responseType: 'stream' }); const imageBuffer = await sharp(response.data).toBuffer();
验证Lambda中获取的图片完整性
虽然Buffer开头看起来正常,但还是要确认Lambda拉取的是完整的图片:- 打印
sourceImageBuffer.length,和图片的实际文件大小对比; - 把Lambda中的
sourceImageBuffer上传到S3,下载后验证是否能正常打开,或者和本地拉取的Buffer做哈希对比,确认内容一致。
- 打印
升级Sharp版本
你当前使用的0.26.1是比较旧的版本(2020年的版本),后续版本修复了很多Lambda环境的兼容性问题,可以尝试升级到较新的稳定版本(比如0.32.x系列),同时确保安装方式符合Lambda的环境要求。检查Lambda的网络和权限细节
虽然已经能获取到Buffer,但偶尔网络波动可能导致图片数据不完整,可以在获取图片后加一步校验,比如检查JPEG的结束标识ff d9是否存在于Buffer末尾。
内容的提问来源于stack exchange,提问作者Gyula Soós

