如何让用户直接把图片上传到对象存储 S3

网友投稿 432 2022-10-10

如何让用户直接把图片上传到对象存储 S3

问题背景

在 Web 和移动应用程序中,为用户提供上传数据的功能是很常见的。您的应用程序可能允许用户上传 PDF 和文件、照片或视频等媒体。每个现代 Web 服务器技术都有允许此功能的机制。通常,在基于服务器的环境中,该过程遵循此流程:

The user uploads the file to the application server. The application server saves the upload to a temporary space for processing. The application transfers the file to a database, file server, or object store for persistent storage.

虽然该过程很简单,但它可能会对繁忙应用程序中的 Web 服务器的性能产生显着的副作用。媒体上传通常很大,因此传输这些媒体可能会占用大量的网络 I/O 和服务器 CPU 时间。您还必须管理传输状态以确保成功上传整个对象,并管理重试和错误。

这对于具有尖峰流量模式的应用程序具有挑战性。例如,在专门发送节日问候的 Web 应用程序中,它可能仅在节假日前后遇到大部分流量。如果成千上万的用户尝试在同一时间上传媒体,这需要您横向扩展应用服务器并确保有足够的网络带宽可用。

通过将这些文件直接上传到 Amazon S3,您可以避免通过您的应用程序服务器代理这些请求。这可以显着减少网络流量和服务器 CPU 使用率,并使您的应用程序服务器能够在繁忙时段处理其他请求。 S3 还具有高可用性和持久性,使其成为用户上传的理想持久存储。

无服务上传到 S3

架构

当您直接上传到 S3 存储桶时,您必须首先从 Amazon S3 服务请求签名 URL。然后,您可以使用签名 URL 直接上传。这是您的应用程序前端的两步过程:

Call an Amazon API Gateway endpoint, which invokes the s3-presigned-url Lambda function. This gets a signed URL from the S3 bucket. Directly upload the file from the application to the S3 bucket.

部署

我们使用 AWS SAM 来部署。

git clone https://github.com/wangzan18/s3-presigned-urls.git cd s3-presigned-urls sam deploy --guided

当部署完成之后,会输出一个 API 的终端节点:

测试

测试为两个步骤,第一步是通过请求获取一个预签名的 URL,第二步是向这个 URL PUT 一个图片。

第一步:

{"url": ""key": "3504834451.jpg"}

可以看到请求成功,我们登录到 S3 看下图片上传如何:

这里需要注意的是,因为我们的预签名 URL 的 Key 名称已经确定了,不管我们上传的图片是什么名称,最终结果都会显示 Key 的名称。

前端测试

在我的代码仓库里面,还有一个前端的页面,可以传到 S3,然后开放公网访问,提交图片。

仅供简单测试,最重要的是后面移动应用如何对接。

模板介绍

template.yaml

这个文件是 SAM 最主要的配置文件,通过这一段参数,创建一个 HTTP API Gateway,允许一些请求参数。

# HTTP API MyApi: Type: AWS::Serverless::HttpApi Properties: # CORS configuration - this is open for development only and should be restricted in prod. # See CorsConfiguration: AllowMethods: - GET - POST - DELETE - OPTIONS AllowHeaders: - "*" AllowOrigins: - "*"

下面这个资源比较重要一步,需要确保 Lambda 对 S3 有写的权限,并且事件驱动为 HTTP API Gateway。

S3PreSignedUrlFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: s3-presigned-url/ Handler: app.lambda_handler Policies: - S3WritePolicy: BucketName: !Ref S3UploadBucket ## This permission allows the Lambda function to request signed URLs ## for objects that will be publicly readable. Uncomment if you want this ACL. # - Statement: # - Effect: Allow # Resource: !Sub 'arn:aws:s3:::${S3UploadBucket}/' # Action: # - s3:putObjectAcl Environment: Variables: UploadBucket: !Ref S3UploadBucket Runtime: python3.7 Events: S3PreSignedApi: Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /upload Method: get ApiId: !Ref MyApi

app.py

整个申请预签名 URL 的函数比较简单,繁琐的功能 SDK 都已经封装好了,函数会自动生成一个随机的 Key,然后返回给请求者一个 URL,通过这个 URL 可以使用 PUT 请求上传参数

import boto3 import json import os import random def lambda_handler(event, context): bucket = os.environ.get('UploadBucket') key = random.getrandbits(32) url = boto3.client('s3').generate_presigned_url( ClientMethod='put_object', Params={'Bucket': bucket, 'Key': str(key) + '.jpg', 'ContentType': 'image/jpeg'}, ExpiresIn=3600) return { "statusCode": 200, "body": json.dumps({ "url": url, "key": str(key) + '.jpg' }), }

需要注意的是,因为我们要上传的是图片,所以需要在 Params 添加一个参数'ContentType': 'image/jpeg'。

参考文档:

欢迎大家扫码关注,获取更多信息

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:zookeeper服务发现实战及原理--spring-cloud-zookeeper分析
下一篇:springboot中使用redis并且执行调试lua脚本
相关文章

 发表评论

暂时没有评论,来抢沙发吧~