使用Amazon S3-Website生成缩略图

191218-head-apigateway

上一篇我们介绍了通过Cloudfront+Lambda@Edge生成缩率图,这篇简单介绍下另一种方式:通过S3静态网站托管实现生成缩略图。实现核心就是配置当S3返回404时,重定向到我们自己的图片处理服务完成缩略图创建。在这种配置下,我们需要指定Cloudfront的源为S3静态网站地址

S3静态网站地址格式:{bucketName}.s3-website-{region}.amazonaws.com
S3地址格式:{bucketName}.s3-{region}.amazonaws.com

S3Website+EC2

方案架构

from https://amazonaws-china.com/cn/blogs/china/image-processing-service-based-on-s3/

流程说明

1.客户端请求200x200的缩略图
2.S3中未存在图片,返回302状态码(此处实际应该使用307状态码)
3.客户端请求EC2上的图片处理服务
4.图片处理服务按照规则获取S3上原图
5.图片处理服务生成200x200的缩略图
6.将缩略图返回给客户端
7.将缩略图上传到S3中,方便下次访问

主要服务部署

静态网站托管(S3-website)

在第2步中需要使用S3静态网站支持,才能返回307状态码:

191218-s3website

设置重定向规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<RoutingRules>
<RoutingRule>
<Condition>
<KeyPrefixEquals/>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals> <!-- 配置404规则 -->
</Condition>
<Redirect>
<Protocol>https</Protocol>
<HostName>imgzoom.example.com</HostName> <!-- 重定向域名 -->
<ReplaceKeyPrefixWith>resize?src=</ReplaceKeyPrefixWith> <!-- 重定向地址,src的值为图片的key -->
<HttpRedirectCode>307</HttpRedirectCode> <!-- 状态码307重定向 -->
</Redirect>
</RoutingRule>
</RoutingRules>

EC2部署

EC2上需要部署图片处理服务,可以使用任意合适的代码,同时还需要新的图片处理域名配合S3使用。
核心处理逻辑为下载原图,生成缩略图,上传缩略图至S3,返回缩略图给客户端。

S3Website+Lambda+APIGateway

这种方案可以看成是替换了方案一的EC2:
1.用Lambda替换图片处理服务
2.用APIGateWay替换EC2的网关配置

方案架构

from https://amazonaws-china.com/cn/blogs/compute/resize-images-on-the-fly-with-amazon-s3-aws-lambda-and-amazon-api-gateway/

流程说明

1.客户端请求缩略图
2.S3中未存在图片,返回307状态码
3.客户端请求APIGateway
4.APIGateway调用Lambda
5.Lambda执行图片处理,将生成的缩略图上传至S3
6.APIGateway返回301状态码
7.客户端重新请求缩略图

主要服务部署

静态网站托管(S3-website)

同方案一,重定向规则中的hostName替换成APIGateway域名

Lambda函数

Lambda函数实现方式可以使用多种语言,javanodejsgolang都可以。
核心处理逻辑为下载原图,生成缩略图,上传缩略图至S3,返回301状态码通知客户端重新请求。

其他

静态网站托管返回307

一般情况下S3会与Cloudfront配合使用,按照Cloudfront文档说明(CloudFront 如何处理来自源的 HTTP 3xx 状态代码),307状态码CloudFront不会重定向新位置:

在 CloudFront 从 Amazon S3 存储桶或自定义源服务器中请求对象时,源有时会返回 HTTP 3xx 状态代码,这通常表示 URL 已更改(301 Moved Permanently 或 307 Temporary Redirect)或在 CloudFront 上次请求后未更改对象 (304 Not Modified)。CloudFront 将按照 CloudFront 分配中的设置指定的持续时间以及从源随对象一起返回的标头字段缓存 3xx 响应。

如果源返回 301 或 307 状态代码,则 CloudFront 将不会重定向到新位置。

Cloudfront缓存了重定向

如果Cloudfront缓存了重定向,Stackoverflow上提供了一种处理方案
在”Cloudfront分配”-“行为”中按照缩略图格式创建行为,将该行为的默认TTL设置为0,并且将该行为优先级设置为0:
191218-cloudfront-bhavior
在上传缩略图时设置缓存时间:

1
2
3
4
5
6
7
8
S3.putObject({
Body: buffer,
Bucket: bucket,
ContentType: 'image/' + requiredFormat,
CacheControl: 'max-age=2592000', // 设置cloudfront缓存时间
Key: key,
StorageClass: 'STANDARD'
})

APIGateway实现302重定向

在APIGateway的响应中添加状态码为302,并设置请求头Location,映射值设置为需要跳转的URL,可以参考这篇博文:How to return a 302 with Location header using API Gateway and Lambda

参考

基于S3的图片处理服务
Resize Images on the Fly with Amazon S3, AWS Lambda, and Amazon API Gateway
SERVERLESS IMAGE RESIZE WITH AMAZON LAMBDA FUNCTION
A crash course on Serverless with AWS - Image resize on-the-fly with Lambda and S3
Lambda开发人员指南