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

使用boto3生成S3预签名Post时Content-Type重复问题解决

解决S3预签名Post上传后Content-Type重复问题

在用boto3生成S3预签名Post实现前端上传图片时,上传后的文件Content-Type变成了image/png,image/png,出现重复值。相关代码如下:

后端Python(boto3)代码

s3_client = boto3.client('s3')
response = s3_client.generate_presigned_post(
    "bucket",
    "logo",
    Fields={
        "Content-Type": "image/png"
    },
    Conditions=[
        ["starts-with", "$Content-Type", "image/"],
    ],
    ExpiresIn=3600
)

预签名返回示例

{
    "url": "https://s3.amazonaws.com/bucket",
    "fields": {
        "Content-Type": "image/png",
        "key": "logo",
        "AWSAccessKeyId": "ABC",
        "policy": "blahblah",
        "signature": "XYZ123"
    }
}

前端JavaScript代码

const formData  = new FormData();
for (const key in json.fields) {
  formData.append(key, json.fields[key]);
}
formData.append("file", image);
return fetch(json.url, {
  method: "POST",
  body: formData
});

问题原因

出现重复是因为FormData里同时包含了预签名返回的Content-Type字段,以及file对象自身携带的Content-Type,S3会将这两个值合并成逗号分隔的形式。

解决方法

方案1:固定Content-Type(仅允许image/png)

  1. 修改后端代码:移除Fields里的Content-Type,同时把Conditions改为精确匹配image/png,确保只有该类型的文件能上传:
s3_client = boto3.client('s3')
response = s3_client.generate_presigned_post(
    "bucket",
    "logo",
    Fields={
        # 移除Content-Type字段
    },
    Conditions=[
        ["eq", "$Content-Type", "image/png"],
    ],
    ExpiresIn=3600
)
  1. 修改前端代码:循环添加字段时跳过Content-Type,同时可以手动指定文件的Content-Type(或直接使用文件自身的):
const formData  = new FormData();
for (const key in json.fields) {
  if (key === "Content-Type") continue;
  formData.append(key, json.fields[key]);
}
// 手动指定类型,或直接用image本身的type
formData.append("file", image, { type: "image/png" });
return fetch(json.url, {
  method: "POST",
  body: formData
});

方案2:支持多种图片类型

如果需要允许所有图片类型上传,只需要调整后端和前端代码,不再手动添加Content-Type字段:

  1. 后端代码:移除Fields里的Content-Type,保留starts-with的条件:
s3_client = boto3.client('s3')
response = s3_client.generate_presigned_post(
    "bucket",
    "logo",
    Fields={
        # 不指定Content-Type
    },
    Conditions=[
        ["starts-with", "$Content-Type", "image/"],
    ],
    ExpiresIn=3600
)
  1. 前端代码:同样跳过Content-Type字段,直接上传文件,使用文件自身的Content-Type:
const formData  = new FormData();
for (const key in json.fields) {
  if (key === "Content-Type") continue;
  formData.append(key, json.fields[key]);
}
formData.append("file", image);
return fetch(json.url, {
  method: "POST",
  body: formData
});

这样处理后,S3只会使用单一的Content-Type值,不会出现重复的情况。

内容的提问来源于stack exchange,提问作者timborden

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:13:12