使用亚马逊(AWS)云服务在S3上实现图片缩放功能(CloudFront/S3[AccessPoint/LambdaAccessPoint])

亚马逊云服务中的S3对象存储功能和国内阿里云的oss对象存储使用基本一致。但是涉及到存储内容处理时,两家有些差别。

比如:对于云存储中的图片资源,阿里云比较人性化对于基本的缩放裁剪功能已经帮我们封装好了,只需要在url地址后面拼接参数即可,但是亚马逊S3存储本身并不具备这个功能,但是亚马逊提供了很多种方式,虽然灵活但是使用门槛较高(尤其是亚马逊文档基本都是英文的🤣)。

下面详细说一下如何在亚马逊服务上基于S3存储实现图片处理(扩展开可以处理任意类型存储资源)

篇幅较长,看完能懂个大概

使用到的亚马逊服务:

Lambda函数服务:云服务商目前都在推的serverless一种实现,在云端特定功能上运行写好的代码,支持很多种语言,弹性扩展灵活方便。参考(首先要学会简单的创建lambda函数,后面需要使用函数处理图片)

S3对象存储:

        Access Point:作为S3存储的一个外部访问入口,一个access point对应一个S3bucket,一个S3 bucket可以对应多个access point. 常用于外部访问S3存储数据。

        Object Lambda Access Point:建立在Access Point之上的Lambda函数切点,可以对访问请求或者响应做进一步处理,或者修改。

CloudFront云端内容分发服务(cdn):亚马逊云端内容分发服务,实现对内容的实时定制化处理,可扩展性高,延迟低。

S3 + CloudFront + Lambda 实现图片缩放具体步骤

1. 在lambda控制台新建Lambda函数 参考:geting-started 本文所需代码如下:

注:代码来自亚马逊文档中的示例,稍作修改实现图片缩放功能

import boto3
import json
import os
import logging
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from urllib import request
from urllib.parse import urlparse, parse_qs, unquote
from urllib.error import HTTPError
from typing import Optionallogger = logging.getLogger('S3-img-processing')
logger.addHandler(logging.StreamHandler())
logger.setLevel(getattr(logging, os.getenv('LOG_LEVEL', 'INFO')))
FILE_EXT = {'JPEG': ['.jpg', '.jpeg'],'PNG': ['.png'],'TIFF': ['.tif']
}
OPACITY = 64  # 0 = transparent and 255 = full soliddef get_img_encoding(file_ext: str) -> Optional[str]:result = Nonefor key, value in FILE_EXT.items():if file_ext in value:result = keybreakreturn result# 添加水印示例
def add_watermark(img: Image, text: str) -> Image:# font = ImageFont.truetype("AmazonEmber_Rg.ttf", 82)txt = Image.new('RGBA', img.size, (255, 255, 255, 0))if img.mode != 'RGBA':image = img.convert('RGBA')else:image = imgd = ImageDraw.Draw(txt)# Positioning Textwidth, height = image.sizetext_width, text_height = d.textsize(text, font)x = width / 2 - text_width / 2y = height / 2 - text_height / 2# Applying Textd.text((x, y), text, fill=(255, 255, 255, OPACITY), font=font)# Combining Original Image with Text and Savingwatermarked = Image.alpha_composite(image, txt)return watermarked# 图片缩放
def resize_image(img, max_side_length=768):# 打开图像文件width, height = img.sizeprint("原:宽X高", width, "x", height)# 计算缩放后的尺寸scale_factor = max_side_length / max(width, height)new_width = int(width * scale_factor)new_height = int(height * scale_factor)# 缩放图像resized_img = img.resize((new_width, new_height))return resized_imgdef handler(event, context) -> dict:logger.debug(json.dumps(event))object_context = event["getObjectContext"]# Get the presigned URL to fetch the requested original object# from S3s3_url = object_context["inputS3Url"]# Extract the route and request token from the input contextrequest_route = object_context["outputRoute"]request_token = object_context["outputToken"]parsed_url = urlparse(event['userRequest']['url'])object_key = parsed_url.pathlogger.info(f'Object to retrieve: {object_key}')parsed_qs = parse_qs(parsed_url.query)for k, v in parsed_qs.items():parsed_qs[k][0] = unquote(v[0])filename = os.path.splitext(os.path.basename(object_key))# Get the original S3 object using the presigned URLlogger.info(f'S3 url: {s3_url}, parsed_url: {parsed_url}')req = request.Request(s3_url)try:response = request.urlopen(req)except HTTPError as e:logger.info(f'Error downloading the object. Error code: {e.code}')logger.exception(e.read())return {'status_code': e.code}if encoding := get_img_encoding(filename[1].lower()):logger.info(f'Compatible Image format found! Processing image: {"".join(filename)}')img = Image.open(response)logger.debug(f'Image format: {img.format}')logger.debug(f'Image mode: {img.mode}')logger.debug(f'Image Width: {img.width}')logger.debug(f'Image Height: {img.height}')# img_result = add_watermark(img, parsed_qs.get('X-Amz-watermark', ['Watermark'])[0])img_result = imgif parsed_qs.get('size', [''])[0] != '':img_result = resize_image(img, int(parsed_qs.get('size', ['500'])[0], base=10))img_bytes = BytesIO()if img.mode != 'RGBA':# Watermark added an Alpha channel that is not compatible with JPEG. We need to convert to RGB to saveimg_result = img_result.convert('RGB')img_result.save(img_bytes, format='JPEG')else:# Will use the original image format (PNG, GIF, TIFF, etc.)img_result.save(img_bytes, encoding)img_bytes.seek(0)transformed_object = img_bytes.read()else:logger.info(f'File format not compatible. Bypass file: {"".join(filename)}')transformed_object = response.read()# Write object back to S3 Object Lambdas3 = boto3.client('s3')# The WriteGetObjectResponse API sends the transformed dataif os.getenv('AWS_EXECUTION_ENV'):s3.write_get_object_response(Body=transformed_object,RequestRoute=request_route,RequestToken=request_token)else:# Running in a local environment. Saving the file locallywith open(f'myImage{filename[1]}', 'wb') as f:logger.debug(f'Writing file: myImage{filename[1]} to the local filesystem')f.write(transformed_object)# Exit the Lambda function: return the status codereturn {'status_code': 200}

创建完成如下:

2. 亚马逊S3控制台左侧 Access Point 菜单创建Access Point

3.   亚马逊S3控制台左侧 Object Lambda Access Point 菜单创建Object Lambda Access Point

 其他选项保持默认,点击创建Object Lambda Access Point即可

4. CloudFront控制台创建分发

其他先保持默认,点击创建分发。

 5. 上面分别创建了所需资源,下面需要为上面创建的资源和S3 bucket配置访问策略权限。

      配置Bucket访问策略 ,点击bucket name名称进入下图,最后点击Bucket policy右侧的edit编辑按钮

 修改如下配置,保存。 (下面的配置为允许aws的所有服务访问s3内的指定bucket内所有对象,并且AccessPoint的账号等于指定的账号)

{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"AWS": "*"},"Action": "*","Resource": ["arn:aws:s3:::你的bucket名称","arn:aws:s3:::你的bucket名称/*"],"Condition": {"StringEquals": {"s3:DataAccessPointAccount": "当前登录的账号ID"}}}]
}

 配置Access Point访问策略

配置内容如下:(下面配置为允许lambda access point访问点  访问  当前 access point内所有对象资源)

{"Version": "2012-10-17","Id": "default","Statement": [{"Sid": "s3objlambda","Effect": "Allow","Principal": {"Service": "cloudfront.amazonaws.com"},"Action": "s3:*","Resource": ["arn:aws:s3:你的区域:当前帐号ID:accesspoint/你的AccessPoint名子标识(我这里是vapp-aws-image)","arn:aws:s3:你的区域:当前帐号ID:accesspoint/你的AccessPoint名子标识/object/*"],"Condition": {"ForAnyValue:StringEquals": {"aws:CalledVia": "s3-object-lambda.amazonaws.com"}}}]
}

配置Object Lambda Access Point访问策略

 配置策略如下:(下面的配置为允许登陆账号下的内容分发  访问指定的object lambda access point)

{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Service": "cloudfront.amazonaws.com"},"Action": "s3-object-lambda:Get*","Resource": "arn:aws:s3-object-lambda:你的区域:登录账号ID:accesspoint/你的ObjectLambdaAccessPoint名字","Condition": {"StringEquals": {"aws:SourceArn": "arn:aws:cloudfront::登录账号ID:distribution/刚才创建的分发ID"}}}]
}

6. 资源和策略配置完成后,还有最后一步就是自定义访问参数,用于缓存生成的内容,避免每次访问都需要调用lambda函数处理(或者缓存了不正确的内容,因为默认缓存策略不包含自定义参数),本文自定义参数为size,表示当前图片最大边边长尺寸,等比缩放,需要为自定义参数创建一个Cache policy

 

 创建成功后,找到刚才创建的CloudFront分发,配置缓存策略如下:

 保存后,等会(几分钟)生效。

7. 测试

CloudFront控制台,找到刚才创建的Distribution分发,找到分发域名,如下图:

 到bucket中上传一个图片,然后使用该域名访问测试如下:

如果写的lambda函数有问题,会报错,到lambda控制台查找日志根据报错信息调试即可。 

 上面截图中使用的为英文版控制台,原因是由于亚马逊很多文档都是英文,个别有中文的翻译也不好,对比英文文档使用时会出现对不上号的情况,所以推荐大家使用亚马逊对应文档操作时使用英文控制台。

最后 理一下这套服务整个流程

参考:amazon-s3-object-lambda-with-cloudfront

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/2206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bean 作用域与生命周期

Bean 作用域与生命周期 ​ 对于 Spring 来说,核心操作对象就是存和取 Bean ,接下来就 Bean 的作用域与生命周期进行探讨。 文章目录 Bean 作用域与生命周期一、作用域的定义1.1、Bean 的6种作用域1.2、Bean作用域设置方法 二、Bean 的生命周期2.1、Bean…

postgresql还原bak

1、第一步肯定是要新建自己还原的目标数据库,例如: 2、进入postgresql的安装目录下的bin目录下 然后地址栏输入cmd进入命令 输入以下 psql -h localhost -U postgres -p 5432 -d SamsinoYardStandard_karamay -f "D:\desktop\zk\20230628.bak&quo…

verilog实现数码管静态显示

文章目录 verilog实现数码管静态显示一、任务要求二、实验代码三、仿真代码四、仿真结果五、总结 verilog实现数码管静态显示 一、任务要求 六个数码管同时间隔0.5s显示0-f。要求:使用一个顶层模块,调用计时器模块和数码管静态显示模块。 二、实验代码…

将Spring Boot项目打包部署到阿里云linux服务器

首先 你要保证自己的服务器上有java环境 如果没有可以参考我的文章 linux服务器中安装java JDK1.8版本 然后 我们打开我们的Spring Boot项目 双击 package 生命周期进行打包 打包完成之后 我们找到 target 下面会有一个jar包 然后 我们右键它 如下图操作 系统就会帮你打开它所…

OpenCV for Python 学习第四天 :通道的获取与合并

上一篇博客,我们学习了如何通过更快的item()和itemset()的方法访问图片,以及了解了图像的兴趣位置的获取方法,那么今天,我们将学习通道的处理方法,通过通道的拆分和合并的实例,让大家更好的了解咱们有关于B…

前端笔记_OAuth规则机制下实现个人站点接入qq三方登录

文章目录 ⭐前言⭐qq三方登录流程💖qq互联中心创建网页应用💖配置回调地址redirect_uri💖流程分析 ⭐思路分解⭐技术选型实现💖技术选型:💖实现 ⭐结束 ⭐前言 大家好,我是yma16,本…

JMeter做http接口功能测试

1. 普通的以key-value传参的get请求 e.g. 获取用户信息 添加http请求;填写服务器域名或IP;方法选GET;填写路径;添加参数;运行并查看结果。 2. 以Json串传参的post请求 e.g. 获取用户余额 添加http请求;…

设计模式-原型模式

目录 一、传统方式 二、原型模式 三、浅拷贝和深拷贝 克隆羊问题: 现在有一只羊tom,姓名为: tom,年龄为: 1,颜色为: 白色,请编写程序创建和tom羊属性完全相同的10只羊。 一、传统方式 public class Client {public static vo…

WMTS 地图切片Web服务 协议数据解析

1. WMTS 描述 WMTS(Web Map Tiles Service):地图切片Web服务。 2. 数据示例: arcgis online 导出的wmts xml: https://sampleserver6.arcgisonline.com/arcgis/rest/services/WorldTimeZones/MapServer/WMTS 内容解析: contents中可能包…

J2EEJSP自定义标签库01out标签if标签

目录 一.什么是标签 二.JSP自定义标签库 2.1 JSP标签库是什么 2.2 处理流程 2.3 如何自定义标签 2.4 标签类型 三.开发示例 3.1 out标签 1.创建助手类 2.编写tld(标签库的描述)文件,(必须放在WEB-INF目录或其目录下&a…

python爬虫-获取headers(报文头)关键参数实例小记

注意!!!!某XX网站逆向实例仅作为学习案例,禁止其他个人以及团体做谋利用途!!! 第一步:请求页面,得到响应。建议首次请求时headers内容都带着,调试…

react报错信息

报错信息 render函数里dom不能直接展示obj对象 取变量记得要有{} https://segmentfault.com/q/1010000009619339 这样在写的时候就已经执行方法了,所以此处用箭头函数()》{}才会在点击时执行或者 遍历数据使用map来遍历,使用forea…

Docker【安装与基本使用】

【1】Docker的安装 注意:如果之前安装过docker其他版本,请删除干净。 docker-01 10.0.0.51 2G docker-02 10.0.0.52 2G docker-01 [rootdocker-01 ~]# cp -rp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime cp: overwrite ‘/etc/localtime’? …

H3C-Cloud Lab实验-OSPF配置实验

一、实验拓扑图 实验需求: 1、按照图示配置 IP 地址 2、按照图示分区域配置 OSPF ,实现全网互通 3、为了路由结构稳定,要求路由器使用环回口作为 Router-id,ABR 的环回口宣告进骨干区域 4、掌握OSPF初始化流程、路由表学习的过…

el-progress组件使用,样式修改,自定义文字

正常的el-progress显示是这样的 修改后 自动计算percentage&#xff0c;format自定义显示文字 <template><div><div class"content-view"><div v-for"(item, index) in progressList" class"item-view"><el-prog…

解锁编程世界的魔法密码:探索算法的奥秘与应用

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~* 一&#xff1a;引言 算法是解决问题和优化程序性能的核心&#xff0c;它是一…

你真的会用async和await么?

async函数搞懂 背景asyncawaitawait 知识点1await 知识点2await 知识点三await 知识点四await 知识点五 背景 背景就是遇到了一个比较烦人的模块&#xff0c;里面的涉及到了大量的async 和 awiat。发现大多人对这个语法糖一知半解&#xff0c;然后大量的滥用&#xff0c;整理一…

数据标注的类型有哪些?

构建像人类一样的AI或ML模型需要大量训练数据。要使模型做出决定并采取行动&#xff0c;就必须通过数据标注来训练模型&#xff0c;使其能够理解特定信息。 但是&#xff0c;什么是数据标注呢&#xff1f;数据标注是指对用于人工智能应用的数据进行分类和标注。我们必须针对特定…

Qt6 Qt Quick UI原型学习QML第二篇

Qt6 Qt Quick UI原型学习QML第二篇 界面效果QML语法语法讲解核心要素项目元素矩形元素文本元素图像元素MouseArea元素 界面效果 QML语法 import QtQuick 2.12 import QtQuick.Window 2.12Window {id: rootvisible: truewidth: 640height: 480title: qsTr("QML学习第二篇&…

用微服务架构推进企业数字化转型升级

随着数字化转型进入深水区&#xff0c;企业应用程序建设需求急剧增长且变化多端&#xff0c;软件架构经历了单体结构、垂直架构、SOA架构&#xff0c;发展到了现在的微服务架构。 单体架构目前应用较多&#xff0c;部署容易&#xff0c;但单体式应用内部包含了所有需要的服务&…