You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)"

问题分析与解决方案

核心问题

  1. S3返回的Body是流对象,Axios直接传递无法匹配LinkedIn要求
    curl的--upload-file是直接读取文件二进制内容作为请求体,但你从S3拿到的Body是ReadableStream。Axios直接传递流时,可能没有正确处理内容编码或传输方式,导致LinkedIn无法解析请求体。

  2. 缺少Content-Type请求头
    curl会自动识别文件类型并设置对应的Content-Type(比如image/jpeg),但你的代码里没有添加这个头。LinkedIn API需要明确知道上传的资源类型,缺少它会直接返回400错误。

  3. 未将流转换为完整的二进制数据
    流是分段传输的,直接传给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:07:39