

# 使用预签名 URL 上传对象
<a name="PresignedUrlUploadObject"></a>



您可以使用预签名 URL 来允许他人将对象上传到您的 Amazon S3 存储桶。使用预签名 URL 将允许在不要求另一方拥有 Amazon 安全凭证或权限的情况下进行上传。预签名 URL 受创建它的用户的权限所限制。也即，如果您收到预签名 URL 来上传对象，则仅当该 URL 的创建者拥有上传该对象所需的权限时，您才能上传对象。

当有人使用该 URL 上传对象时，Amazon S3 将在指定的存储桶中创建对象。如果存储桶中已存在具有预签名 URL 中指定的相同键的对象，则 Amazon S3 会将现有对象替换为上传的对象。上传后，存储桶拥有者将拥有该对象。

有关预签名 URL 的一般信息，请参阅[使用预签名 URL 下载和上传对象](using-presigned-url.md)。

可以使用适用于 Visual Studio 的 Amazon Explorer 生成预签名 URL 来上传对象，而不需要编写任何代码。也可以使用 Amazon SDK 以编程方式生成预签名 URL。

**注意**  
目前，Amazon Toolkit for Visual Studio 不支持 Visual Studio for Mac。

## 使用 Amazon Toolkit for Visual Studio (Windows)
<a name="upload-object-presignedurl-vsexplorer"></a>

1. 按照《Amazon Toolkit for Visual Studio User Guide》**中的 [Installing and setting up the Toolkit for Visual Studio](https://docs.amazonaws.cn/toolkit-for-visual-studio/latest/user-guide/setup.html) 中的说明安装 Amazon Toolkit for Visual Studio。

1. 使用以下步骤（《Amazon Toolkit for Visual Studio 用户指南》**中的[连接到 Amazon](https://docs.amazonaws.cn/AWSToolkitVS/latest/UserGuide/connect.html)）连接到 Amazon。

1. 在标有 **Amazon 各区服务浏览器**的左侧面板中，右键单击要向其中上传对象的存储桶。

1. 选择**创建预签名 URL...**。

1. 在弹出窗口中，设置预签名 URL 的到期日期和时间。

1. 在**对象键**中，设置要上传的文件的名称。您上传的文件必须与该名称完全匹配。如果具有相同对象键的对象已位于存储桶中，Amazon S3 会将现有对象替换为新上传的对象。

1. 选择 **PUT** 可指定此预签名 URL 将用于上传对象。

1. 选择 **Generate（生成）**按钮。

1. 要将此 URL 复制到剪贴板，请选择 **Copy（复制）**。

1. 要使用此 URL，您可以通过 `curl` 命令发送 PUT 请求。包括您的文件的完整路径以及预签名 URL 本身。

   ```
   curl -X PUT -T "/path/to/file" "presigned URL"
   ```

## 使用 Amazon SDK 生成 `PUT` 预签名 URL 来上传文件
<a name="presigned-urls-upload-sdk"></a>

 您可以生成可在有限时间内执行 S3 操作的预签名 URL。

**注意**  
如果您使用 Amazon CLI 或 Amazon SDK，则预签名 URL 的到期时间可设置为多达 7 天。有关更多信息，请参阅[预签名 URL 的到期时间](https://docs.amazonaws.cn/AmazonS3/latest/userguide/using-presigned-url.html#PresignedUrl-Expiration)。

------
#### [ Python ]

 以下 Python 脚本生成一个 `PUT` 预签名 URL，用于将对象上传到 S3 通用存储桶。

1. 复制脚本的内容并将其保存为“*put-only-url.py*”文件。要使用以下示例，请将*用户输入占位符*替换为您自己的信息（例如，您的文件名）。

   ```
   import argparse
   import boto3
   from botocore.exceptions import ClientError
   
   def generate_presigned_url(s3_client, client_method, method_parameters, expires_in):
       """
       Generate a presigned Amazon S3 URL that can be used to perform an action.
       
       :param s3_client: A Boto3 Amazon S3 client.
       :param client_method: The name of the client method that the URL performs.
       :param method_parameters: The parameters of the specified client method.
       :param expires_in: The number of seconds the presigned URL is valid for.
       :return: The presigned URL.
       """
       try:
           url = s3_client.generate_presigned_url(
               ClientMethod=client_method,
               Params=method_parameters,
               ExpiresIn=expires_in
           )
       except ClientError:
           print(f"Couldn't get a presigned URL for client method '{client_method}'.")
           raise
       return url
   
   def main():
       parser = argparse.ArgumentParser()
       parser.add_argument("bucket", help="The name of the bucket.")
       parser.add_argument(
           "key", help="The key (path and filename) in the S3 bucket.",
       )
       parser.add_argument(
           "--region", help="The AWS region where the bucket is located.", default="us-east-1"
       )
       parser.add_argument(
           "--content-type", help="The content type of the file to upload.", default="application/octet-stream"
       )
       args = parser.parse_args()
       
       # Create S3 client with explicit region configuration
       s3_client = boto3.client("s3", region_name=args.region)
       
       # Optionally set signature version if needed for older S3 regions
       # s3_client.meta.config.signature_version = 's3v4'
       
       # The presigned URL is specified to expire in 1000 seconds
       url = generate_presigned_url(
           s3_client, 
           "put_object", 
           {
               "Bucket": args.bucket, 
               "Key": args.key,
               "ContentType": args.content_type  # Specify content type
           }, 
           1000
       )
       print(f"Generated PUT presigned URL: {url}")
   
   if __name__ == "__main__":
       main()
   ```

1. 要生成 `PUT` 预签名 URL 来上传文件，请使用您的存储桶名称和所需的对象路径运行以下脚本。

    以下命令使用的是示例值。将*用户输入占位符*替换为您自己的信息。

   ```
   python put-only-url.py amzn-s3-demo-bucket <object-path> --region us-east-1 --content-type application/octet-stream
   ```

   该脚本将输出一个 `PUT` 预签名 URL：

   ```
   Generated PUT presigned URL: https://amzn-s3-demo-bucket.s3.amazonaws.com/object.txt?AmazonAccessKeyId=AKIAIOSFODNN7EXAMPLE&Signature=vjbyNxybdZaMmLa%2ByT372YEAiv4%3D&Expires=1741978496
   ```

1. 现在，可以使用通过 curl 生成的预签名 URL 来上传文件。请确保包含与生成 URL 时所用的相同内容类型：

   ```
   curl -X PUT -T "path/to/your/local/file" -H "Content-Type: application/octet-stream" "generated-presigned-url"
   ```

   如果在生成 URL 时指定了不同的内容类型，请确保在 curl 命令中使用该相同的内容类型。

有关使用 Amazon SDK 生成预签名 URL 来上传对象的更多示例，请参阅 [Create a presigned URL for Amazon S3 by using an Amazon SDK](https://docs.amazonaws.cn/AmazonS3/latest/API/s3_example_s3_Scenario_PresignedUrl_section.html)。

**对 SignatureDoesNotMatch 错误进行故障排除**  
如果您在使用预签名 URL 时遇到 `SignatureDoesNotMatch` 错误，请检查以下各项：  
验证系统时间与可靠的时间服务器同步
确保您使用的 URL 与生成的 URL 完全一致，没有任何修改
检查 URL 是否已过期，并在需要时生成一个新的 URL
确保上传请求中的内容类型与生成 URL 时指定的内容类型相匹配
确认您使用的是正确的存储桶区域
使用 curl 时，请将 URL 用引号括起来，以便正确地处理特殊字符

------