Serverless Function

Date
Created
Jul 24, 2025 09:46 AM
Descrption
不断优化
Tags
前端工程化
架构设计

notion image

Serverless Function 是什么?

Serverless Function(无服务器函数)是一种事件驱动的计算服务,开发者只需要编写业务代码,无需管理服务器基础设施。代码在需要时自动运行,按实际使用量计费。

主要特点

  • 按需执行:只在被调用时运行
  • 自动扩缩容:根据请求量自动伸缩
  • 按使用计费:只为实际执行时间付费
  • 无服务器管理:无需关心底层基础设施
  • 事件驱动:通过各种事件触发执行

适用场景

1. API 端点和微服务

// Vercel Functions 示例 export default function handler(req, res) { if (req.method === 'POST') { const { email, message } = req.body; // 处理联系表单 await sendEmail(email, message); res.status(200).json({ success: true }); } }
适合:
  • RESTful API
  • GraphQL 端点
  • 轻量级微服务
  • 不需要持久连接的服务

2. 数据处理和 ETL

# AWS Lambda 示例 import json import boto3 def lambda_handler(event, context): s3 = boto3.client('s3') # S3 对象创建事件触发 bucket = event['Records'][0]['s3']['bucket']['name'] key = event['Records'][0]['s3']['object']['key'] # 处理上传的文件 if key.endswith('.csv'): process_csv_file(bucket, key) elif key.endswith('.json'): process_json_file(bucket, key) return { 'statusCode': 200, 'body': json.dumps('File processed successfully') }
适合:
  • 文件上传后处理
  • 数据转换和清洗
  • 日志分析
  • 批量数据处理

3. 定时任务和 Cron Jobs

// Netlify Functions 示例 exports.handler = async (event, context) => { // 每日数据备份 if (event.httpMethod === 'POST') { try { await backupDatabase(); await sendNotification('Backup completed successfully'); return { statusCode: 200, body: JSON.stringify({ message: 'Backup completed' }) }; } catch (error) { return { statusCode: 500, body: JSON.stringify({ error: error.message }) }; } } };
适合:
  • 定时数据同步
  • 清理过期数据
  • 发送定时通知
  • 健康检查

4. 事件响应处理

// Cloudflare Workers 示例 addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const url = new URL(request.url) // 根据不同路径处理不同事件 switch (url.pathname) { case '/webhook/payment': return handlePaymentWebhook(request) case '/webhook/user': return handleUserWebhook(request) default: return new Response('Not found', { status: 404 }) } }
适合:
  • Webhook 处理
  • 第三方服务集成
  • 实时通知
  • 事件驱动架构

5. 图像/媒体处理

# AWS Lambda + PIL 示例 import boto3 from PIL import Image import io def lambda_handler(event, context): s3 = boto3.client('s3') bucket = event['bucket'] key = event['key'] # 下载原始图像 response = s3.get_object(Bucket=bucket, Key=key) image = Image.open(io.BytesIO(response['Body'].read())) # 生成多种尺寸的缩略图 sizes = [(150, 150), (300, 300), (800, 600)] for size in sizes: resized = image.resize(size, Image.Resampling.LANCZOS) # 保存到 S3 buffer = io.BytesIO() resized.save(buffer, format='JPEG') thumbnail_key = f"thumbnails/{size[0]}x{size[1]}/{key}" s3.put_object( Bucket=bucket, Key=thumbnail_key, Body=buffer.getvalue(), ContentType='image/jpeg' ) return {'statusCode': 200, 'body': 'Thumbnails generated'}

主流平台使用方式

1. Vercel Functions

// api/hello.js export default function handler(req, res) { const { name = 'World' } = req.query; res.status(200).json({ message: `Hello ${name}!` }); } // api/users/[id].js - 动态路由 export default async function handler(req, res) { const { id } = req.query; const user = await getUserById(id); res.json(user); }
部署:
npm install -g vercel vercel deploy

2. Netlify Functions

// netlify/functions/contact.js exports.handler = async (event, context) => { const { httpMethod, body } = event; if (httpMethod !== 'POST') { return { statusCode: 405, body: 'Method Not Allowed' }; } const { email, message } = JSON.parse(body); // 发送邮件逻辑 await sendEmail(email, message); return { statusCode: 200, body: JSON.stringify({ success: true }) }; };
配置文件 (netlify.toml):
[build] functions = "netlify/functions" [[redirects]] from = "/api/*" to = "/.netlify/functions/:splat" status = 200

3. AWS Lambda

// index.js const AWS = require('aws-sdk'); const dynamodb = new AWS.DynamoDB.DocumentClient(); exports.handler = async (event) => { const { httpMethod, pathParameters, body } = event; try { switch (httpMethod) { case 'GET': return await getUser(pathParameters.id); case 'POST': return await createUser(JSON.parse(body)); case 'PUT': return await updateUser(pathParameters.id, JSON.parse(body)); case 'DELETE': return await deleteUser(pathParameters.id); default: return { statusCode: 405, body: JSON.stringify({ message: 'Method not allowed' }) }; } } catch (error) { return { statusCode: 500, body: JSON.stringify({ error: error.message }) }; } };
部署配置 (serverless.yml):
service: my-api provider: name: aws runtime: nodejs18.x region: us-east-1 functions: api: handler: index.handler events: - http: path: users/{id} method: any cors: true - http: path: users method: post cors: true

4. Cloudflare Workers

addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const url = new URL(request.url) // KV 存储操作 if (url.pathname.startsWith('/api/cache/')) { const key = url.pathname.split('/').pop() if (request.method === 'GET') { const value = await MY_KV.get(key) return new Response(value || 'Not found', { status: value ? 200 : 404 }) } if (request.method === 'POST') { const value = await request.text() await MY_KV.put(key, value) return new Response('Stored successfully') } } // 代理请求 if (url.pathname.startsWith('/proxy/')) { const targetUrl = url.pathname.replace('/proxy/', '') return fetch(targetUrl) } return new Response('Hello World!') }

最佳实践场景分析

✅ 适合使用 Serverless 的场景

  1. 不规律的流量
    1. // 营销活动 API export default async function handler(req, res) { // 可能突然有大量请求,也可能长时间无请求 const campaign = await processCampaignData(req.body); res.json(campaign); }
  1. 简单的 CRUD 操作
    1. // 博客文章 API export default async function handler(req, res) { switch (req.method) { case 'GET': return res.json(await getPosts()); case 'POST': return res.json(await createPost(req.body)); } }
  1. 事件驱动的处理
    1. // 文件上传处理 exports.handler = async (event) => { const { bucket, key } = event.Records[0].s3; await processUploadedFile(bucket, key); };

❌ 不适合的场景

  1. 需要持久连接的应用
    1. // WebSocket 连接 - 不适合 // 长轮询 - 不适合 // 实时聊天 - 建议用传统服务器
  1. 高计算密集型任务
    1. # 复杂的机器学习训练 - 不适合 # 大数据分析 - 可能超时 # 视频渲染 - 资源限制
  1. 需要本地状态的应用
    1. // 需要内存缓存的应用 // 需要本地文件系统的应用 // 需要持久化连接池的应用

成本考虑

// 成本优化示例 export default async function handler(req, res) { // 避免冷启动 - 重用连接 if (!global.dbConnection) { global.dbConnection = await createDbConnection(); } // 早期返回减少执行时间 if (!req.body.email) { return res.status(400).json({ error: 'Email required' }); } // 批量处理减少调用次数 const results = await processBatch(req.body.items); res.json(results); }
成本特点:
  • 低流量:非常便宜,甚至免费
  • 中等流量:通常比传统服务器便宜
  • 高流量:可能比传统服务器贵
  • 执行时间:按毫秒计费,优化代码很重要
Serverless Functions 特别适合构建现代 Web 应用的 API、处理异步任务、响应事件等场景,是 JAMStack 架构的重要组成部分。