7.4 KiB
7.4 KiB
API 文档
API 概述
项目使用 Next.js API Routes 实现服务端接口,主要用于处理联系表单提交等后端逻辑。
基础信息
- 基础 URL:
/api - 内容类型:
application/json - 字符编码:
UTF-8
接口列表
1. 联系表单 API
提交联系表单
接口地址
POST /api/contact
请求头
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| Content-Type | string | 是 | application/json |
请求参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| name | string | 是 | 联系人姓名 |
| string | 是 | 联系人邮箱 | |
| phone | string | 否 | 联系人电话 |
| subject | string | 是 | 咨询主题 |
| message | string | 是 | 咨询内容 |
| website | string | 否 | 蜜罐字段(用于反垃圾) |
| submitTime | string | 否 | 表单提交时间戳 |
| mathHash | string | 否 | 数学验证码哈希 |
| mathTimestamp | string | 否 | 数学验证码时间戳 |
| mathAnswer | number | 否 | 数学验证码答案 |
请求示例
{
"name": "张三",
"email": "zhangsan@example.com",
"phone": "13800138000",
"subject": "产品咨询",
"message": "我想了解贵公司的软件开发服务。",
"submitTime": "1709827200000",
"mathHash": "MTAwLTE3MDk4MjcxMDAwMDA=",
"mathTimestamp": "1709827100000",
"mathAnswer": 100
}
响应参数
| 参数 | 类型 | 描述 |
|---|---|---|
| success | boolean | 请求是否成功 |
| message | string | 成功消息(成功时) |
| error | string | 错误消息(失败时) |
成功响应
{
"success": true,
"message": "消息已发送,我们会尽快与您联系!"
}
错误响应
{
"success": false,
"error": "请填写必填字段"
}
错误码说明
| HTTP 状态码 | 错误信息 | 描述 |
|---|---|---|
| 200 | - | 蜜罐字段被填充(静默拒绝) |
| 400 | 请填写必填字段 | 缺少必填字段 |
| 400 | 请输入有效的邮箱地址 | 邮箱格式不正确 |
| 400 | 提交过快,请稍后再试 | 提交时间间隔过短 |
| 400 | 验证码错误,请重新计算 | 数学验证码错误 |
| 500 | 发送失败,请稍后重试 | 邮件发送失败 |
安全机制
1. 蜜罐字段 (Honeypot)
通过隐藏字段 website 检测机器人提交:
// 前端隐藏字段
<input name="website" className="hidden" tabIndex={-1} autoComplete="off" />
// 后端检测
if (website) {
// 检测到机器人,静默返回成功
return NextResponse.json({ success: true });
}
2. 提交时间验证
验证表单提交时间间隔,防止快速自动提交:
if (submitTime) {
const timeDiff = Date.now() - parseInt(submitTime);
if (timeDiff < 2000) {
// 提交过快,拒绝请求
return NextResponse.json({ success: false, error: '提交过快' });
}
}
3. 数学验证码
使用数学运算验证码防止机器人:
// 前端生成验证码
const num1 = Math.floor(Math.random() * 10) + 1;
const num2 = Math.floor(Math.random() * 10) + 1;
const answer = num1 + num2;
const timestamp = Date.now();
const hash = btoa(`${answer}-${timestamp}`);
// 后端验证
const expectedHash = btoa(`${mathAnswer}-${mathTimestamp}`);
if (expectedHash !== mathHash) {
return NextResponse.json({ success: false, error: '验证码错误' });
}
4. 邮箱验证
验证邮箱格式:
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return NextResponse.json({ success: false, error: '请输入有效的邮箱地址' });
}
5. XSS 防护
使用 DOMPurify 清理用户输入:
import DOMPurify from 'dompurify';
const sanitizedName = DOMPurify.sanitize(name);
邮件服务
Resend 配置
项目使用 Resend 服务发送邮件:
RESEND_API_KEY=re_xxxxx
COMPANY_EMAIL=contact@novalon.cn
邮件模板
邮件使用 HTML 模板,包含:
- 公司品牌头部
- 表单数据展示
- 时间戳信息
- 响应式设计
邮件模板结构
<html>
<head>
<style>
/* 响应式样式 */
</style>
</head>
<body>
<div class="container">
<div class="header">
<!-- 公司品牌 -->
</div>
<div class="content">
<!-- 表单数据 -->
</div>
<div class="footer">
<!-- 页脚信息 -->
</div>
</div>
</body>
</html>
Server Actions
联系表单 Server Action
位于 src/app/(marketing)/contact/actions.ts:
'use server';
export async function submitContactForm(formData: FormData) {
// 服务端表单处理逻辑
}
优势:
- 无需创建 API 路由
- 自动 CSRF 保护
- 类型安全
- 更简洁的错误处理
环境变量
必需配置
# Resend API 密钥
RESEND_API_KEY=re_xxxxx
# 公司邮箱
COMPANY_EMAIL=contact@novalon.cn
可选配置
# 环境
NODE_ENV=production
# 站点 URL
NEXT_PUBLIC_SITE_URL=https://www.novalon.cn
请求限制
速率限制
建议在生产环境配置速率限制:
// 示例:使用 Upstash Redis
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '1 m'),
});
const { success } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json({ error: '请求过于频繁' }, { status: 429 });
}
CORS 配置
API 路由默认不允许跨域请求。如需配置 CORS:
export async function POST(request: NextRequest) {
const response = NextResponse.json({ success: true });
response.headers.set('Access-Control-Allow-Origin', 'https://www.novalon.cn');
response.headers.set('Access-Control-Allow-Methods', 'POST');
return response;
}
错误处理
统一错误响应格式
interface ApiResponse {
success: boolean;
message?: string;
error?: string;
data?: unknown;
}
错误日志
try {
await resend.emails.send({ ... });
} catch (error) {
console.error('邮件发送失败:', error);
return NextResponse.json(
{ success: false, error: '发送失败,请稍后重试' },
{ status: 500 }
);
}
测试接口
使用 cURL
curl -X POST http://localhost:3000/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "测试用户",
"email": "test@example.com",
"subject": "测试主题",
"message": "测试消息内容"
}'
使用 Playwright
// e2e/src/tests/api/contact.spec.ts
test('提交联系表单', async ({ request }) => {
const response = await request.post('/api/contact', {
data: {
name: '测试用户',
email: 'test@example.com',
subject: '测试主题',
message: '测试消息内容',
},
});
expect(response.ok()).toBeTruthy();
const data = await response.json();
expect(data.success).toBe(true);
});
API 版本控制
当前项目 API 不包含版本号。如需版本控制,建议:
/api/v1/contact
/api/v2/contact
监控与日志
推荐集成
- Sentry - 错误监控
- LogRocket - 会话回放
- Vercel Analytics - 性能监控
日志格式
console.log({
timestamp: new Date().toISOString(),
level: 'info',
message: '联系表单提交',
data: { email, subject },
});