news 2026/10/31 14:48:16

Serverless Examples:用 AWS Lambda 从 URL 拉取文件并存入 S3 的 Node.js 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Serverless Examples:用 AWS Lambda 从 URL 拉取文件并存入 S3 的 Node.js 实战
  • 示例工程

【免费下载链接】examples

Serverless Examples – A collection of boilerplates and examples of serverless architectures built with the Serverless Framework on AWS Lambda, Microsoft Azure, Google Cloud Functions, and more.

项目地址:https://gitcode.com/gh_mirrors/exa/examples
点击查看免费下载

本文基于 Serverless Examples 仓库中的 aws-node-fetch-file-and-store-in-s3 示例,讲解如何用一个 Node.js Lambda 函数从远程 URL 抓取文件(如图片),再通过 AWS SDK v3 的PutObjectCommand将其上传到 S3 存储桶。读完本文,你可以掌握:完整的serverless.yml配置(含 IAM 权限、自动创建的 S3 资源)、基于 ESM 的 Lambda 处理函数实现细节,以及部署(serverless deploy)和本地调用(serverless invoke)的完整操作流程。

适用场景与整体思路

该示例的定位很明确——从远程来源(URL)获取文件,然后上传到 S3 存储桶。README 中给出的典型用例是:

  • 保存来自其他服务的用户头像(Store a user's profile picture from another service)。

实际项目中这类需求非常普遍:用户在注册时只提供了一个第三方头像 URL(例如某个 CDN 或社交媒体头像链接),如果你的业务只希望引用自己 S3 桶内的资源(避免第三方链接失效、跨域问题或内容被篡改),就需要一个"中转"步骤把文件抓取下来并持久化到自己的存储桶里。

整个流程只有三步:

  1. Lambda 函数接收事件,其中包含image_url(要抓取的远程文件地址)和key(上传到桶内使用的对象 Key);
  2. 函数用内置的fetch拉取远程数据,转成Buffer;
  3. 调用 S3 的PutObjectCommand把Buffer作为Body写入桶中。

README 给出的核心逻辑就是这几行:

const response = await fetch(event.image_url); const buffer = Buffer.from(await response.arrayBuffer()); await s3.send(new PutObjectCommand({ Bucket, Key, Body: buffer }));

下面结合仓库中的真实源码 handler.js 和 serverless.yml 逐层展开。

处理函数实现:handler.js 逐行解析

完整的 handler.js 内容如下:

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; const s3 = new S3Client({}); export const save = async (event) => { const response = await fetch(event.image_url); if (!response.ok) { throw new Error(`Failed to fetch ${response.url}: ${response.status} ${response.statusText}`); } const buffer = Buffer.from(await response.arrayBuffer()); return s3.send( new PutObjectCommand({ Bucket: process.env.BUCKET, Key: event.key, Body: buffer, }) ); };

这里有几个值得注意的实现细节:

基于 ESM 的模块写法

文件使用import导入 AWS SDK v3,并且处理函数用export const save导出。这与 package.json 中的"type": "module"声明相配合——Lambda 会把它当作 ES Module 加载。对应的,serverless.yml 中 handler 的写法是handler: handler.save,即指向handler.js中名为save的命名导出函数。

使用全局 fetch 抓取远程文件

代码直接调用全局fetch(event.image_url),没有引入node-fetch、axios等任何额外的 HTTP 库。这依赖 Node.js 18+ 内置的undici全局fetch。从 serverless.yml 可以看到运行时声明为runtime: nodejs24.x,因此该写法在当前仓库示例中是成立的;如果把代码搬回 Node 16 或更低版本,就需要自行引入第三方 fetch 实现。

抓取后先用response.ok判断 HTTP 状态,非 2xx/3xx 时抛出包含 URL、状态码和状态文本的错误;成功后通过response.arrayBuffer()拿到二进制内容,再用Buffer.from(...)转成 Node.js 的Buffer,作为 S3 上传的Body。

S3Client 实例在模块顶层创建

s3客户端在模块加载时就实例化了(const s3 = new S3Client({})),而不是在每次调用时新建。AWS SDK v3 的客户端对象是无状态、可复用的,放在顶层可以复用连接池,是 Lambda 冷启动优化的常见做法。注意new S3Client({})没有传region等显式配置——它会依赖 Lambda 运行时的默认凭据链(从执行角色读取)和环境变量中自动解析区域,因此这个函数能写入桶,前提条件是执行角色被授予了相应权限,这一点由serverless.yml中的 IAM 配置保证,见下一节。

事件入参与桶名注入

函数从event.image_url和event.key读取入参,桶名则来自环境变量process.env.BUCKET——不在代码里硬编码桶名,而是由部署时注入(桶名是 CloudFormation 生成的全局唯一名称)。这与部署输出中Deploying "fetch-file-and-store-in-s3" to stage "dev" (us-west-1)的场景一致。

serverless.yml:资源、权限与环境变量

serverless.yml 的完整内容:

service: fetch-file-and-store-in-s3 frameworkVersion: '4' provider: name: aws runtime: nodejs24.x architecture: arm64 stage: dev region: us-west-1 iam: role: statements: - Effect: Allow Action: - s3:PutObject - s3:PutObjectAcl Resource: !Sub "${UploadBucket.Arn}/*" functions: save: handler: handler.save environment: BUCKET: !Ref UploadBucket resources: Resources: UploadBucket: Type: AWS::S3::Bucket

这份配置覆盖了示例能"零手工配置直接部署"所需的全部要素:

  • provider:AWS 平台、nodejs24.x运行时、arm64架构(Graviton,按 vCPU/GB 计费更划算且性能更强)、dev阶段、us-west-1区域。
  • IAM 权限:通过provider.iam.role.statements给默认执行角色追加一条策略——只允许s3:PutObject和s3:PutObjectAcl两个动作,且资源限定为!Sub "${UploadBucket.Arn}/*",即该桶下的所有对象(object)。这遵循最小权限原则:函数没有读取、删除桶内对象的权限,也没有其他服务的权限。
  • 环境变量:BUCKET: !Ref UploadBucket把 CloudFormation 资源UploadBucket的逻辑引用(即生成的真实桶名)注入 Lambda 的环境变量,与handler.js中的process.env.BUCKET对应。
  • 自定义资源:resources.Resources中声明了一个AWS::S3::Bucket(逻辑 ID 为UploadBucket)。README 强调:存储桶会作为这个 stack 的一部分被自动创建,桶名由 CloudFormation 生成的全局唯一名称,无需任何手工创建。

也就是说,这个示例唯一的第三方依赖就是@aws-sdk/client-s3,见 package.json:

"dependencies": { "@aws-sdk/client-s3": "^3.700.0" }

部署与调用

安装依赖与部署

先安装依赖:

npm install

然后部署:

serverless deploy

部署完成的预期输出类似:

Deploying "fetch-file-and-store-in-s3" to stage "dev" (us-west-1) ✔ Service deployed to stack fetch-file-and-store-in-s3-dev (42s) functions: save: fetch-file-and-store-in-s3-dev-save (1.2 kB)

可以看到函数名会被生成为<service>-<stage>-<function>(fetch-file-and-store-in-s3-dev-save),函数打包后只有 1.2 kB(因为唯一的依赖@aws-sdk/client-s3会在打包时一并带上,这里的 1.2 kB 是 handler 自身大小展示)。

用 serverless invoke 本地触发测试

部署后可以直接用serverless invoke向函数发送事件测试:

serverless invoke --function save --log --data='{ "image_url": "https://assets-cdn.github.com/images/modules/open_graph/github-mark.png", "key": "github.png"}'

预期输出类似:

"S3 saved"

以及 Lambda 的执行报告:

START RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3 Version: $LATEST END RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3 REPORT RequestId: c658859d-bd11e6-ac1f-c7a7ee5bd7f3 Duration: 436.94 ms Billed Duration: 500 ms Memory Size: 1024 MB Max Memory Used: 29 MB

函数返回值是s3.send(...)的 Promise,即PutObjectCommand的响应结果(README 展示的是早期 SDK 响应的"Saved"形态;从当前仓库源码看,返回值就是PutObjectCommand的完整响应对象)。调用完成后,可以去 CloudWatch Logs 查看日志,或直接到 S3 控制台检查github.png这个对象是否已存在于部署时创建的桶中。

扩展阅读:Lambda 并发上限与扩容

README 的 Scaling 一节指出:默认情况下,AWS Lambda 对同一区域内所有函数的总并发执行数限制为 100。这个默认限制是一个安全阀,用于在开发和测试初期保护你免于因失控或递归函数产生的意外成本。如果业务增长需要更高的并发,可以通过 AWS 控制台提交"请求提高并发执行上限"(Request a limit increase for concurrent executions)来调整账户级并发配额。

对这个"抓文件存 S3"的用法而言,并发上限通常不是瓶颈——真正的约束往往是远程 URL 的响应速度和单文件体积(整个文件会被读进内存再上传),在生产环境里还应考虑超时、重试与文件大小校验等问题,这些在当前示例中均未处理,属于按需自行加固的扩展点。

小结

该示例用不到 20 行的 handler.js 和一份 29 行的 serverless.yml,完整演示了 Serverless Framework v4 下"远程文件 → Lambda → S3"这一经典数据落盘链路:

  • 全局fetch+Buffer完成远程二进制抓取;
  • @aws-sdk/client-s3的PutObjectCommand完成上传;
  • IAM 语句把权限收敛到目标桶对象级;
  • AWS::S3::Bucket自定义资源 +!Ref/!Sub实现桶的自动创建与名称注入,避免硬编码。

如需进一步学习同仓库中其他"文件入 S3"的变体,可以参考 aws-node-s3-file-replicator(S3 事件驱动的桶间复制)与 aws-node-signed-uploads(签名直传)。

  • 示例工程

【免费下载链接】examples

Serverless Examples – A collection of boilerplates and examples of serverless architectures built with the Serverless Framework on AWS Lambda, Microsoft Azure, Google Cloud Functions, and more.

项目地址:https://gitcode.com/gh_mirrors/exa/examples
点击查看免费下载
上一篇:Mod Organizer 2终极指南:从零开始掌握游戏模组管理的5个秘诀
下一篇:Falcon 安装完全指南:PyPy/CPython 选型、Cython 加速与 WSGI/ASGI 服务器部署

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/1 9:05:48

Ollama本地运行大模型:从入门到模型选型实战指南

最近经常有人拿着各种配置单来问我&#xff1a;本地跑大模型到底用什么工具&#xff1f;该选多大的模型&#xff1f;我的笔记本扛得住吗&#xff1f;然后我基本都会先反问一句&#xff1a;你用Ollama了吗&#xff1f;对方十有八九会说&#xff0c;听说过这名字&#xff0c;但Ol…

作者头像 李华
网站建设 2026/11/1 9:05:18

Qwen-Image-2.1 云端部署保姆级教程:Linux+Gradio+GPU实战

1. 项目概述&#xff1a;为什么你需要在云端跑通 Qwen-Image-2.1&#xff1f;Qwen-Image-2.1 是阿里通义实验室发布的多模态大模型&#xff0c;它不是简单地“看图说话”&#xff0c;而是能完成图像理解、图文生成、视觉推理、图像编辑、OCR增强、跨模态检索等一整套高阶任务。…

作者头像 李华
网站建设 2026/11/1 9:05:56

Python全栈开发:从入门到实战的学习路径

1. 项目概述&#xff1a;为什么选择Python作为全栈开发语言&#xff1f;Python作为一门语法简洁、生态丰富的编程语言&#xff0c;已经成为全栈开发领域的热门选择。我在过去五年带过上百名零基础学员&#xff0c;发现Python的学习曲线明显比其他语言平缓。新手在第一天就能写出…

作者头像 李华
网站建设 2026/11/1 9:06:37

Go语言实战指南:从类型方法到并发惯用法的常用方法全梳理

每次有人问“Go 的常用方法有哪些”&#xff0c;我都得先反问一句&#xff1a;你是想要一份 API 清单&#xff0c;还是想知道真正写业务代码时每天都离不开的那套打法&#xff1f;因为 Go 的文档其实已经够全了&#xff0c;真正拉开差距的&#xff0c;是你知不知道某个方法在什…

作者头像 李华
网站建设 2026/10/26 19:20:35

不懂设计,也能做出好海报。

说清楚“你要什么”&#xff0c;剩下的交给它。生成赛博朋克风格戴眼镜的猫我们其实一直在做海报社团招新要一张报名图&#xff0c;小店开业要一张促销图&#xff0c;比赛报名要一张通道图&#xff0c;读书会、生日会、二手转卖、社群分享……这些事背后都没有一个“设计部门”…

作者头像 李华
网站建设 2026/10/29 2:25:44

MySQL 4.1.11源码包编译运行与数据迁移实战指南

简介&#xff1a;这是一份 MySQL 4.1.11 的 .tar.gz 源码包&#xff0c;面向需要在 Linux/Unix 环境编译旧版数据库、排查遗留系统或研究数据库早期实现的技术人员。作为 4.x 分支的代表性发布&#xff0c;包体完整收录服务器、客户端及配套工具的源码与构建脚本。包内共有 454…

作者头像 李华