Serverless Functions #

什么是 Serverless Functions? #

Serverless Functions 是无需管理服务器即可运行后端代码的服务。Netlify 基于 AWS Lambda 提供函数托管。

text
HTTP 请求 → Netlify Function → 执行代码 → 返回响应

优势 #

优势 说明
无服务器管理 专注代码,无需运维
自动扩展 根据请求量自动伸缩
按需计费 只为实际执行付费
全球部署 边缘节点执行

快速开始 #

创建函数目录 #

text
项目根目录/
├── netlify/
│   └── functions/
│       └── hello.js
├── netlify.toml
└── package.json

第一个函数 #

javascript
// netlify/functions/hello.js
exports.handler = async (event, context) => {
  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      message: 'Hello World!'
    })
  }
}

访问函数 #

text
https://your-site.netlify.app/.netlify/functions/hello

函数配置 #

netlify.toml 配置 #

toml
[build]
  command = "npm run build"
  publish = "dist"
  functions = "netlify/functions"

[functions]
  directory = "netlify/functions"
  node_bundler = "esbuild"

函数目录结构 #

text
netlify/functions/
├── hello.js           # 单文件函数
├── api/
│   ├── users.js       # /api/users
│   └── posts.js       # /api/posts
└── complex/
    ├── index.js       # 函数入口
    ├── utils.js       # 辅助模块
    └── package.json   # 依赖

函数签名 #

基本结构 #

javascript
exports.handler = async (event, context) => {
  // event: 请求信息
  // context: 运行时上下文
  
  return {
    statusCode: 200,
    headers: {},
    body: ''
  }
}

Event 对象 #

javascript
{
  "httpMethod": "POST",
  "path": "/api/users",
  "queryStringParameters": {
    "page": "1"
  },
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer xxx"
  },
  "body": "{\"name\":\"张三\"}",
  "isBase64Encoded": false
}

Context 对象 #

javascript
{
  "awsRequestId": "xxx",
  "logGroupName": "/aws/lambda/xxx",
  "functionName": "xxx",
  "functionVersion": "$LATEST",
  "identity": {},  // 用户身份信息
  "user": {}       // Netlify Identity 用户
}

处理请求 #

GET 请求 #

javascript
exports.handler = async (event) => {
  const { page = 1, limit = 10 } = event.queryStringParameters || {}
  
  const users = await getUsers(page, limit)
  
  return {
    statusCode: 200,
    body: JSON.stringify({ users })
  }
}

POST 请求 #

javascript
exports.handler = async (event) => {
  if (event.httpMethod !== 'POST') {
    return { statusCode: 405, body: 'Method Not Allowed' }
  }
  
  const data = JSON.parse(event.body)
  
  const user = await createUser(data)
  
  return {
    statusCode: 201,
    body: JSON.stringify(user)
  }
}

处理文件上传 #

javascript
exports.handler = async (event) => {
  if (!event.isBase64Encoded) {
    return { statusCode: 400, body: 'Invalid content' }
  }
  
  const fileBuffer = Buffer.from(event.body, 'base64')
  const contentType = event.headers['content-type']
  
  // 处理文件...
  
  return {
    statusCode: 200,
    body: JSON.stringify({ success: true })
  }
}

响应格式 #

成功响应 #

javascript
return {
  statusCode: 200,
  headers: {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*'
  },
  body: JSON.stringify({
    success: true,
    data: {}
  })
}

错误响应 #

javascript
return {
  statusCode: 400,
  body: JSON.stringify({
    success: false,
    error: 'Invalid request'
  })
}

重定向 #

javascript
return {
  statusCode: 302,
  headers: {
    Location: 'https://example.com'
  },
  body: ''
}

环境变量 #

访问环境变量 #

javascript
exports.handler = async (event) => {
  const apiKey = process.env.API_KEY
  const dbUrl = process.env.DATABASE_URL
  
  // 使用环境变量...
}

配置环境变量 #

toml
[build.environment]
  API_KEY = "your-api-key"

[context.production.environment]
  DATABASE_URL = "postgres://..."

数据库操作 #

连接数据库 #

javascript
const { Pool } = require('pg')

let pool

const getPool = () => {
  if (!pool) {
    pool = new Pool({
      connectionString: process.env.DATABASE_URL,
      ssl: { rejectUnauthorized: false }
    })
  }
  return pool
}

exports.handler = async (event) => {
  const pool = getPool()
  const result = await pool.query('SELECT * FROM users')
  
  return {
    statusCode: 200,
    body: JSON.stringify(result.rows)
  }
}

使用 MongoDB #

javascript
const { MongoClient } = require('mongodb')

let client

const getClient = async () => {
  if (!client) {
    client = new MongoClient(process.env.MONGODB_URI)
    await client.connect()
  }
  return client
}

exports.handler = async (event) => {
  const client = await getClient()
  const db = client.db('mydb')
  const users = await db.collection('users').find({}).toArray()
  
  return {
    statusCode: 200,
    body: JSON.stringify(users)
  }
}

外部 API 调用 #

GET 请求 #

javascript
exports.handler = async (event) => {
  const response = await fetch('https://api.example.com/users', {
    headers: {
      'Authorization': `Bearer ${process.env.API_KEY}`
    }
  })
  
  const data = await response.json()
  
  return {
    statusCode: 200,
    body: JSON.stringify(data)
  }
}

POST 请求 #

javascript
exports.handler = async (event) => {
  const body = JSON.parse(event.body)
  
  const response = await fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.API_KEY}`
    },
    body: JSON.stringify(body)
  })
  
  const data = await response.json()
  
  return {
    statusCode: 201,
    body: JSON.stringify(data)
  }
}

TypeScript 支持 #

配置 #

toml
[functions]
  directory = "netlify/functions"
  node_bundler = "esbuild"

TypeScript 函数 #

typescript
// netlify/functions/hello.ts
import { Handler } from '@netlify/functions'

interface Response {
  message: string
  timestamp: number
}

export const handler: Handler = async (event, context) => {
  const response: Response = {
    message: 'Hello World!',
    timestamp: Date.now()
  }
  
  return {
    statusCode: 200,
    body: JSON.stringify(response)
  }
}

本地开发 #

启动本地开发服务器 #

bash
netlify dev

访问本地函数 #

text
http://localhost:8888/.netlify/functions/hello

调试函数 #

javascript
exports.handler = async (event) => {
  console.log('Event:', JSON.stringify(event, null, 2))
  
  // 你的代码...
}

查看日志:

bash
netlify dev

函数日志 #

查看日志 #

text
Site overview → Functions → 选择函数 → Logs

CLI 查看日志 #

bash
netlify functions:log hello

定时函数 #

配置定时触发 #

toml
[functions."scheduled-task"]
  schedule = "0 0 * * *"

定时函数示例 #

javascript
// netlify/functions/scheduled-task.js
exports.handler = async (event) => {
  console.log('定时任务执行:', new Date().toISOString())
  
  // 执行定时任务...
  
  return {
    statusCode: 200,
    body: 'OK'
  }
}

Cron 表达式 #

表达式 说明
0 0 * * * 每天 0 点
0 */6 * * * 每 6 小时
0 0 * * 0 每周日 0 点
0 0 1 * * 每月 1 日 0 点

函数限制 #

执行限制 #

限制项 免费方案 Pro 方案
执行时间 10 秒 26 秒
内存 1024 MB 1024 MB
包大小 50 MB 50 MB

调用限制 #

限制项 免费方案 Pro 方案
每月调用 125,000 2,000,000

最佳实践 #

1. 复用连接 #

javascript
// 好的做法:复用数据库连接
let connection

const getConnection = async () => {
  if (!connection) {
    connection = await createConnection()
  }
  return connection
}

2. 错误处理 #

javascript
exports.handler = async (event) => {
  try {
    // 业务逻辑
    return { statusCode: 200, body: 'OK' }
  } catch (error) {
    console.error('Error:', error)
    return { 
      statusCode: 500, 
      body: JSON.stringify({ error: 'Internal Server Error' })
    }
  }
}

3. 输入验证 #

javascript
exports.handler = async (event) => {
  if (event.httpMethod !== 'POST') {
    return { statusCode: 405, body: 'Method Not Allowed' }
  }
  
  let body
  try {
    body = JSON.parse(event.body)
  } catch {
    return { statusCode: 400, body: 'Invalid JSON' }
  }
  
  if (!body.name) {
    return { statusCode: 400, body: 'Name is required' }
  }
  
  // 处理请求...
}

4. CORS 处理 #

javascript
const headers = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'Content-Type',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS'
}

exports.handler = async (event) => {
  if (event.httpMethod === 'OPTIONS') {
    return { statusCode: 200, headers, body: '' }
  }
  
  return {
    statusCode: 200,
    headers,
    body: JSON.stringify({ message: 'OK' })
  }
}

下一步 #

掌握了 Serverless Functions 后,继续学习 重定向规则 了解 URL 重定向配置!

最后更新:2026-03-28