Lambda Node.js从S3取图片上传LinkedIn API报400错误排查
问题:Lambda Node.js上传图片至LinkedIn API返回400错误?
我正在编写一个Lambda Node.js函数,需要从S3获取图片后上传至LinkedIn API,但持续收到400响应。请问此实现方式中的问题出在哪里?
代码示例
const client = new S3Client({region: "eu-west-2", credentials: { accessKeyId: "**accesskeyid", secretAccessKey: "**secretaccesskey**"}}); const { Body } = await client.send(new GetObjectCommand({ Bucket: bucketName, Key: key, })); var headers = { "Authorization": "Bearer " + token, "LinkedIn-Version": "202309", "X-Restli-Protocol-Version": "2.0.0" }; axios.put(url, Body, { headers: headers }) .then(function(response){ resolve(response.data); }) .catch(function (error) { reject(error); });
可正常运行的curl命令
curl -i --upload-file **thefile** -H 'Authorization: Bearer **token**' "**theurl**"
Cloudwatch错误日志
"message": "Request failed with status code 400", "name": "AxiosError", "stack": "AxiosError: Request failed with status code 400\n at settle (file:///var/task/node_modules/axios/lib/core/settle.js:19:12)\n at Unzip.handleStreamEnd (file:///var/task/node_modules/axios/lib/adapters/http.js:570:11)\n at Unzip.emit (node:events:529:35)\n at endReadableNT (node:internal/streams/readable:1368:12)\n at process.processTicksAndRejections (node:internal/process/task_queues:82:21)"
问题分析与解决方案
核心问题
S3返回的Body是流对象,Axios直接传递无法匹配LinkedIn要求
curl的--upload-file是直接读取文件二进制内容作为请求体,但你从S3拿到的Body是ReadableStream。Axios直接传递流时,可能没有正确处理内容编码或传输方式,导致LinkedIn无法解析请求体。缺少Content-Type请求头
curl会自动识别文件类型并设置对应的Content-Type(比如image/jpeg),但你的代码里没有添加这个头。LinkedIn API需要明确知道上传的资源类型,缺少它会直接返回400错误。未将流转换为完整的二进制数据
流是分段传输的,直接传给Axios可能导致请求体不完整,必须先把流转换成Buffer,确保发送的是完整的图片二进制数据。
修正后的代码
const client = new S3Client({region: "eu-west-2", credentials: { accessKeyId: "**accesskeyid", secretAccessKey: "**secretaccesskey**"}}); // 获取S3对象时同时拿到Content-Type const { Body, ContentType } = await client.send(new GetObjectCommand({ Bucket: bucketName, Key: key, })); // 将S3的流转换为Buffer const imageBuffer = await new Promise((resolve, reject) => { const chunks = []; Body.on('data', chunk => chunks.push(chunk)); Body.on('end', () => resolve(Buffer.concat(chunks))); Body.on('error', reject); }); var headers = { "Authorization": "Bearer " + token, "LinkedIn-Version": "202309", "X-Restli-Protocol-Version": "2.0.0", "Content-Type": ContentType // 复用S3对象的Content-Type,无需手动指定 }; try { const response = await axios.put(url, imageBuffer, { headers }); resolve(response.data); } catch (error) { reject(error); }
关键改动说明
- 从S3响应中获取
ContentType,确保请求头和图片类型完全匹配,避免手动设置出错。 - 将S3的流转换为Buffer,保证Axios发送的是完整的二进制数据,和curl的行为一致。
- 改用
async/await替代Promise链式调用,代码更简洁易读。
内容的提问来源于stack exchange,提问作者Tony Goodchild
相关产品推荐
相关产品推荐

