4、云函数触发器:API网关触发器、定时触发器、对象存储触发器、数据库触发器
触发器这东西,说白了就是云函数的「开关」。没有触发器,你的函数就是一潭死水,啥也干不了。我刚开始接触Serverless时,总觉得触发器就是简单的「谁调谁」,后来踩了不少坑才明白——每种触发器的脾气都不一样,用错了地方,轻则浪费钱,重则线上事故。
今天咱们就把四种最常用的触发器掰开揉碎讲清楚。嗯,这四种基本覆盖了90%以上的业务场景。
4.1 API网关触发器——最常用的入口
API网关触发器,说白了就是把HTTP请求转成函数调用。你写一个RESTful接口,用户发个GET/POST请求,网关收到后直接触发你的云函数。
我个人习惯把API网关触发器分成两类:
- 代理集成:网关把原始请求原封不动丢给函数,你自己解析HTTP头、body、参数。灵活,但代码量大。
- 非代理集成:网关帮你解析好,函数收到的就是格式化好的JSON。省事,但有些高级功能受限。
我在项目中遇到过一个问题:用非代理集成时,网关默认只支持JSON格式的响应。有一次前端非要返回XML,折腾了半天才发现是网关层给拦截了。后来我统一改用代理集成,虽然多写几行解析代码,但心里踏实。
核心要点:API网关触发器适合对外暴露接口,比如用户注册、数据查询、文件上传。但要注意——网关有超时限制,通常30秒左右。长时间任务别走这条路。
来看一个简单的示例,腾讯云的SCF配合API网关:
exports.main_handler = async (event, context) => {
// event里包含了HTTP请求的全部信息
const { httpMethod, path, headers, body } = event;
if (httpMethod === 'GET') {
return {
isBase64Encoded: false,
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'Hello from Serverless!' })
};
}
if (httpMethod === 'POST') {
const data = JSON.parse(body);
// 处理业务逻辑...
return {
statusCode: 201,
body: JSON.stringify({ id: 'new_record_id' })
};
}
};
避坑指南:我曾经在API网关的CORS配置上卡了整整一天。前端发OPTIONS预检请求,网关直接返回403。后来发现——网关的CORS配置和函数的CORS配置是两回事。建议在网关层统一处理CORS,别让函数背这个锅。
4.2 定时触发器——像闹钟一样准时
定时触发器,就是给云函数设个闹钟。到点了,自动执行。你想想看,每天凌晨清理日志、每小时同步数据、每5分钟检查服务健康状态——这些场景都离不开它。
定时触发器的配置方式一般有两种:
| 方式 | 格式 | 示例 | 说明 |
|---|---|---|---|
| Cron表达式 | 秒 分 时 日 月 星期 | 0 0 3 * * * | 每天凌晨3点执行 |
| 固定频率 | 每N分钟/小时/天 | 每30分钟 | 简单粗暴,适合新手 |
我个人更推荐用Cron表达式,虽然写起来麻烦点,但精确到秒,而且可以避开业务高峰期。比如我习惯把数据备份任务设在凌晨4:15,因为4点整是很多系统的自动运维时间,错开能避免资源争抢。
注意:定时触发器的执行时间不是绝对精确的。云平台通常有±1秒的误差。如果你的业务要求毫秒级准时,定时触发器可能不适合你。另外,函数执行时间不能超过定时周期——比如你设了每5分钟执行一次,但函数跑了10分钟还没结束,下一次触发会被跳过或排队。
代码示例,一个简单的定时清理任务:
exports.main_handler = async (event, context) => {
// event里包含触发时间信息
const { Time } = event;
console.log(`定时任务触发于: ${Time}`);
// 清理7天前的临时文件
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
const oldFiles = await listTempFiles(sevenDaysAgo);
for (const file of oldFiles) {
await deleteFile(file.path);
console.log(`已删除: ${file.name}`);
}
return `清理完成,共删除 ${oldFiles.length} 个文件`;
};
4.3 对象存储触发器——文件一上传,函数就干活
对象存储触发器,就是监听存储桶里的文件变化。上传、删除、修改,任何一个动作都能触发函数执行。这玩意儿在图片处理、视频转码、日志分析场景下特别好用。
为什么会这么方便?你想想看,传统架构里你要写个定时任务去轮询文件夹有没有新文件,又low又费资源。对象存储触发器是事件驱动的——文件来了,函数立刻执行,零延迟。
我在项目中遇到过最典型的场景是图片压缩。用户上传一张10MB的高清图,触发器自动调用函数压缩成200KB的缩略图,整个过程用户无感知。嗯,这里要注意——函数执行时间不能太长,否则用户上传完图片要等半天才能看到缩略图。
事件类型:一般支持以下几种——
- cos:ObjectCreated:Put(上传完成)
- cos:ObjectCreated:Post(通过表单上传)
- cos:ObjectCreated:Copy(复制文件)
- cos:ObjectRemove:Delete(删除文件)
代码示例,监听图片上传并生成缩略图:
exports.main_handler = async (event, context) => {
// 解析存储桶事件
const cosEvent = event.Records[0];
const bucket = cosEvent.cos.bucket.name;
const key = cosEvent.cos.object.key;
// 只处理图片文件
if (!key.match(/\.(jpg|jpeg|png|gif)$/i)) {
return '非图片文件,跳过处理';
}
// 下载原图
const imageBuffer = await downloadFromCOS(bucket, key);
// 生成缩略图(假设用sharp库)
const thumbnail = await sharp(imageBuffer)
.resize(200, 200)
.toBuffer();
// 上传缩略图
const thumbKey = key.replace(/(\.\w+)$/, '_thumb$1');
await uploadToCOS(bucket, thumbKey, thumbnail);
return `缩略图已生成: ${thumbKey}`;
};
避坑指南:我曾经犯过一个低级错误——在对象存储触发器里又去写同一个存储桶,结果触发了无限循环。函数上传文件 → 触发函数 → 又上传文件 → 又触发函数... 最后账单爆了。解决方案很简单:在函数里加个判断,只处理特定前缀或后缀的文件,或者把输出文件放到另一个存储桶。
4.4 数据库触发器——数据变了,通知我
数据库触发器,就是监听数据库的变化。增、删、改,任何一个操作都能触发函数。这玩意儿在数据同步、缓存更新、审计日志场景下特别好用。
说白了,数据库触发器就是「Change Data Capture(CDC)」的Serverless实现。传统做法要装个Debezium或者Canal,配置起来麻烦得很。云函数直接帮你搞定,你只需要写业务逻辑。
我个人习惯把数据库触发器用在两个场景:
- 缓存更新:数据库里的用户信息改了,触发器自动刷新Redis缓存
- 数据同步:主库写入数据,触发器同步到ES或数仓
来看一个腾讯云TDSQL触发器的示例:
exports.main_handler = async (event, context) => {
// event里包含数据库变更记录
const { Records } = event;
for (const record of Records) {
const { eventName, eventSource, tableName } = record;
const newImage = record.dynamodb?.NewImage;
const oldImage = record.dynamodb?.OldImage;
console.log(`操作类型: ${eventName}`);
console.log(`表名: ${tableName}`);
if (eventName === 'INSERT') {
// 新数据插入,同步到缓存
await redis.set(`user:${newImage.id}`, JSON.stringify(newImage));
}
if (eventName === 'MODIFY') {
// 数据更新,刷新缓存
await redis.del(`user:${oldImage.id}`);
await redis.set(`user:${newImage.id}`, JSON.stringify(newImage));
}
if (eventName === 'REMOVE') {
// 数据删除,清理缓存
await redis.del(`user:${oldImage.id}`);
}
}
return `处理了 ${Records.length} 条变更记录`;
};
重要提醒:数据库触发器是「最终一致性」的。什么意思?就是数据库写入成功后,触发器可能延迟几毫秒甚至几秒才触发。如果你的业务要求「写入后立即读取到最新数据」,别依赖触发器,直接在业务代码里同步更新缓存。
4.5 四种触发器怎么选?
最后做个总结,方便你快速决策:
| 触发器类型 | 适用场景 | 延迟 | 注意事项 |
|---|---|---|---|
| API网关 | 对外接口、RESTful API | 毫秒级 | 超时限制30秒,不适合长任务 |
| 定时触发器 | 定时任务、数据清理、报表生成 | 秒级 | 执行时间不能超过周期 |
| 对象存储 | 图片处理、视频转码、日志分析 | 毫秒级 | 小心无限循环,区分输入输出桶 |
| 数据库 | 数据同步、缓存更新、审计日志 | 毫秒~秒级 | 最终一致性,不适合强一致场景 |
嗯,四种触发器讲完了。你想想看,其实每种触发器都有自己的「脾气」。API网关适合对外,定时触发器适合后台,对象存储适合文件处理,数据库触发器适合数据联动。用对了地方,你的Serverless应用就能跑得又快又稳。
下一章咱们聊聊「云函数间的通信与编排」,到时候会讲怎么把多个函数串起来完成复杂业务。敬请期待。