Web Forms后端API数据接收处理教程:从基础到实战的完整指南

引言:Web Forms与后端API的完美结合
在现代Web开发中,Web Forms作为前端数据收集的重要工具,与后端API的数据交互是构建动态应用的核心环节。本教程将系统性地讲解如何从零开始构建一个完整的Web Forms后端API数据接收处理系统,涵盖从基础概念到高级实战的全过程。
什么是Web Forms后端API?
Web Forms后端API是指专门用于接收、验证和处理来自Web表单数据的服务器端接口。它充当了前端用户界面与后端数据存储之间的桥梁,确保数据的安全性、完整性和有效性。
为什么需要专门的数据接收处理?
数据验证
:确保用户输入符合预期格式
安全性
:防止恶意数据注入和攻击
业务逻辑
:执行必要的业务规则处理
4.数据持久化:将数据安全存储到数据库
响应处理
:向前端返回适当的反馈信息
第一部分:基础概念与准备工作
1.1 理解HTTP请求方法
在Web Forms数据处理中,主要使用POST和PUT方法:
// 前端示例:使用fetch API发送表单数据
document.getElementById(‘myForm’).addEventListener(‘submit’, async (e) => {
e.preventDefault();

const formData = new FormData(e.target);
const data = Object.fromEntries(formData);

// 发送POST请求到后端API
const response = await fetch(‘/api/form-submission’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
},
body: JSON.stringify(data)
});

const result = await response.json();
console.log(‘API响应:’, result);
});
1.2 数据格式选择
JSON格式
(推荐):
易于解析和生成
支持复杂数据结构
跨语言兼容性好
FormData格式
:
适合文件上传
自动处理multipart/form-data
无需手动设置Content-Type
1.3 环境准备
后端技术栈选择(以Node.js + Express为例)
# 初始化项目
mkdir web-forms-api
cd web-forms-api
npm init -y

# 安装核心依赖
npm install express cors helmet morgan
npm install express-validator # 数据验证
npm install multer # 文件上传处理
npm install dotenv # 环境变量管理

# 开发依赖
npm install –save-dev nodemon
项目结构规划
web-forms-api/
├── config/
│ └── database.js
├── controllers/
│ └── formController.js
├── middleware/
│ ├── validation.js
│ ├── auth.js
│ └── upload.js
├── routes/
│ └── formRoutes.js
├── utils/
│ └── response.js
├── .env
├── .gitignore
├── package.json
└── server.js
第二部分:基础API实现
2.1 创建基础服务器
// server.js – 基础Express服务器
const express = require(‘express’);
const cors = require(‘cors’);
const helmet = require(‘helmet’);
const morgan = require(‘morgan’);
require(‘dotenv’).config();

const app = express();
const PORT = process.env.PORT || 3000;

// 基础中间件
app.use(helmet()); // 安全头
app.use(cors()); // 跨域支持
app.use(morgan(‘dev’)); // 请求日志
app.use(express.json()); // JSON请求体解析
app.use(express.urlencoded({ extended: true })); // URL编码解析

// 健康检查端点
app.get(‘/health’, (req, res) => {
res.json({ status: ‘OK’, timestamp: new Date().toISOString() });
});

// 基础表单处理端点
app.post(‘/api/form/basic’, (req, res) => {
console.log(‘接收到表单数据:’, req.body);

// 简单响应
res.json({
success: true,
message: ‘数据接收成功’,
receivedData: req.body,
timestamp: new Date().toISOString()
});
});

app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
2.2 基础数据验证
// middleware/validation.js – 基础验证中间件
const { body, validationResult } = require(‘express-validator’);

// 基础表单验证规则
const basicFormValidation = [
body(‘username’)
.trim()
.isLength({ min: 3, max: 30 })
.withMessage(‘用户名长度必须在3-30个字符之间’)
.matches(/^[a-zA-Z0-9_]+$/)
.withMessage(‘用户名只能包含字母、数字和下划线’),

body(’email’)
.trim()
.isEmail()
.withMessage(‘请输入有效的邮箱地址’)
.normalizeEmail(),

body(‘age’)
.optional()
.isInt({ min: 1, max: 120 })
.withMessage(‘年龄必须是1-120之间的整数’),

// 验证结果处理
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
errors: errors.array()
});
}
next();
}
];

module.exports = { basicFormValidation };
2.3 完整的基础API示例
// routes/formRoutes.js – 基础路由
const express = require(‘express’);
const router = express.Router();
const { basicFormValidation } = require(‘../middleware/validation’);

// 基础表单处理路由
router.post(‘/basic’, basicFormValidation, (req, res) => {
const { username, email, age } = req.body;

// 业务逻辑处理(这里只是示例)
const processedData = {
username: username.toUpperCase(), // 转换为大写
email: email.toLowerCase(), // 转换为小写
age: age ? parseInt(age) : null,
submissionId: `FORM-${Date.now()}`,
processedAt: new Date().toISOString()
};

// 返回处理结果
res.json({
success: true,
message: ‘基础表单处理完成’,
data: processedData
});
});

module.exports = router;
第三部分:高级数据处理技术
3.1 文件上传处理
// middleware/upload.js – 文件上传配置
const multer = require(‘multer’);
const path = require(‘path’);
const fs = require(‘fs’);

// 确保上传目录存在
const uploadDir = ‘./uploads’;
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}

// 配置存储引擎
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, uploadDir);
},
filename: (req, file, cb) => {
// 生成唯一文件名
const uniqueSuffix = Date.now() + ‘-‘ + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname);
cb(null, file.fieldname + ‘-‘ + uniqueSuffix + ext);
}
});

// 文件过滤器
const fileFilter = (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif|pdf|doc|docx/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);

if (extname && mimetype) {
return cb(null, true);
} else {
cb(new Error(‘只允许上传图片和文档文件’));
}
};

// 配置multer
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024 // 5MB限制
},
fileFilter: fileFilter
});

module.exports = upload;
3.2 复杂表单处理API
// routes/formRoutes.js – 复杂表单处理
const express = require(‘express’);
const router = express.Router();
const upload = require(‘../middleware/upload’);
const { body, validationResult } = require(‘express-validator’);

// 复杂表单验证规则
const complexFormValidation = [
// 个人信息
body(‘personalInfo.name’)
.trim()
.isLength({ min: 2, max: 50 })
.withMessage(‘姓名长度2-50字符’),

body(‘personalInfo.email’)
.isEmail()
.withMessage(‘邮箱格式错误’),

// 地址信息(嵌套对象)
body(‘address.street’)
.trim()
.notEmpty()
.withMessage(‘街道地址不能为空’),

body(‘address.city’)
.trim()
.notEmpty()
.withMessage(‘城市不能为空’),

// 兴趣爱好(数组)
body(‘interests’)
.isArray({ min: 1, max: 5 })
.withMessage(‘请至少选择1个,最多5个兴趣’),

body(‘interests.*’)
.isIn([‘reading’, ‘sports’, ‘music’, ‘travel’, ‘cooking’])
.withMessage(‘无效的兴趣选项’),

// 自定义验证
body(‘password’)
.isLength({ min: 8 })
.withMessage(‘密码至少8位’)
.matches(/\d/)
.withMessage(‘密码必须包含数字’)
.matches(/[a-zA-Z]/)
.withMessage(‘密码必须包含字母’)
];

// 复杂表单处理路由(支持文件上传)
router.post(‘/complex’,
upload.fields([
{ name: ‘avatar’, maxCount: 1 },
{ name: ‘documents’, maxCount: 3 }
]),
complexFormValidation,
(req, res) => {
// 验证结果检查
const errors = validationResult(req);
if (!errors.isEmpty()) {
// 清理已上传的文件
if (req.files) {
Object.values(req.files).flat().forEach(file => {
fs.unlinkSync(file.path);
});
}
return res.status(400).json({ success: false, errors: errors.array() });
}

// 处理文件信息
const fileInfo = {};
if (req.files) {
if (req.files.avatar) {
fileInfo.avatar = {
originalName: req.files.avatar[0].originalname,
filename: req.files.avatar[0].filename,
path: req.files.avatar[0].path,
size: req.files.avatar[0].size
};
}
if (req.files.documents) {
fileInfo.documents = req.files.documents.map(doc => ({
originalName: doc.originalname,
filename: doc.filename,
path: doc.path,
size: doc.size
}));
}
}

// 构建响应数据
const responseData = {
personalInfo: req.body.personalInfo,
address: req.body.address,
interests: req.body.interests,
files: fileInfo,
submissionId: `COMPLEX-${Date.now()}`,
processedAt: new Date().toISOString()
};

res.json({
success: true,
message: ‘复杂表单处理完成’,
data: responseData
});
}
);

module.exports = router;
3.3 数据清洗与转换
// utils/dataProcessor.js – 数据清洗工具
class DataProcessor {
// 清理HTML标签
static sanitizeHTML(input) {
if (typeof input !== ‘string’) return input;
return input.replace(/<[^>]*>/g, ”);
}

// 防止XSS攻击
static escapeHTML(input) {
if (typeof input !== ‘string’) return input;
const map = {
‘&’: ‘&’,
‘<': '<', '>‘: ‘>’,
‘”‘: ‘"’,
“‘”: ‘'’
};
return input.replace(/[&<>“‘]/g, m => map[m]);
}

// 标准化电话号码
static normalizePhone(phone) {
return phone.replace(/\D/g, ”).replace(/^1/, ‘+861’);
}

// 处理地址信息
static processAddress(address) {
if (!address) return null;

// 去除多余空格
const cleaned = address.replace(/\s+/g, ‘ ‘).trim();

// 提取邮编(如果存在)
const zipMatch = cleaned.match(/(\d{6})$/);
const zipCode = zipMatch ? zipMatch[1] : null;

return {
fullAddress: cleaned,
zipCode: zipCode,
normalized: cleaned.replace(zipCode, ”).trim()
};
}

// 处理数组数据
static processArray(input, allowedValues = null) {
if (!Array.isArray(input)) return [];

// 去重并清理
const cleaned = […new Set(input.map(item =>
typeof item === ‘string’ ? item.trim() : item
))];

// 如果有允许值限制,进行过滤
if (allowedValues) {
return cleaned.filter(item => allowedValues.includes(item));
}

return cleaned;
}

// 处理嵌套对象
static processNestedObject(obj, maxDepth = 5) {
if (maxDepth <= 0 || typeof obj !== 'object' || obj === null) { return obj; } const result = Array.isArray(obj) ? [] : {}; for (const [key, value] of Object.entries(obj)) { if (typeof value === 'object' && value !== null) { result[key] = this.processNestedObject(value, maxDepth - 1); } else if (typeof value === 'string') { result[key] = this.escapeHTML(value.trim()); } else { result[key] = value; } } return result; } } module.exports = DataProcessor; 第四部分:实战项目:完整表单处理系统 4.1 项目架构设计 // config/database.js - 数据库连接 const mongoose = require('mongoose'); const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(‘数据库连接失败:’, error.message);
process.exit(1);
}
};

module.exports = connectDB;
4.2 数据模型设计
// models/FormSubmission.js – 表单提交模型
const mongoose = require(‘mongoose’);

const FormSubmissionSchema = new mongoose.Schema({
// 基础信息
formType: {
type: String,
required: true,
enum: [‘contact’, ‘registration’, ‘feedback’, ‘application’]
},

// 提交者信息
submitter: {
name: { type: String, required: true, trim: true },
email: { type: String, required: true, lowercase: true },
phone: { type: String, trim: true },
age: { type: Number, min: 1, max: 120 }
},

// 地址信息(嵌套)
address: {
street: String,
city: String,
state: String,
zipCode: String,
country: { type: String, default: ‘China’ }
},

// 兴趣/偏好(数组)
interests: [{ type: String }],

// 附加信息
message: {
type: String,
trim: true,
maxlength: 1000
},

// 文件上传
attachments: [{
originalName: String,
filename: String,
path: String,
size: Number,
uploadedAt: { type: Date, default: Date.now }
}],

// 元数据
metadata: {
userAgent: String,
ip: String,
submissionTime: { type: Date, default: Date.now },
status: {
type: String,
enum: [‘pending’, ‘processed’, ‘rejected’],
default: ‘pending’
}
},

// 处理结果
processingResult: {
processedAt: Date,
notes: String,
processedBy: String
}
}, {
timestamps: true // 自动添加 createdAt 和 updatedAt
});

// 创建索引
FormSubmissionSchema.index({ ‘submitter.email’: 1 });
FormSubmissionSchema.index({ ‘metadata.submissionTime’: -1 });
FormSubmissionSchema.index({ ‘metadata.status’: 1 });

module.exports = mongoose.model(‘FormSubmission’, FormSubmissionSchema);
4.3 完整控制器实现
// controllers/formController.js – 完整控制器
const FormSubmission = require(‘../models/FormSubmission’);
const DataProcessor = require(‘../utils/dataProcessor’);
const fs = require(‘fs’);
const path = require(‘path’);

class FormController {
// 处理联系表单
static async handleContactForm(req, res) {
try {
const { personalInfo, message, preferences } = req.body;

// 数据清洗
const cleanedData = {
name: DataProcessor.escapeHTML(personalInfo.name),
email: personalInfo.email.toLowerCase(),
phone: personalInfo.phone ? DataProcessor.normalizePhone(personalInfo.phone) : null,
message: DataProcessor.sanitizeHTML(message)
};

// 创建提交记录
const submission = new FormSubmission({
formType: ‘contact’,
submitter: {
name: cleanedData.name,
email: cleanedData.email,
phone: cleanedData.phone
},
message: cleanedData.message,
metadata: {
userAgent: req.get(‘User-Agent’),
ip: req.ip
}
});

await submission.save();

res.json({
success: true,
message: ‘联系表单提交成功’,
submissionId: submission._id,
timestamp: submission.createdAt
});

} catch (error) {
console.error(‘联系表单处理错误:’, error);
res.status(500).json({
success: false,
message: ‘服务器内部错误’,
error: error.message
});
}
}

// 处理注册表单(带文件上传)
static async handleRegistrationForm(req, res) {
try {
const { personalInfo, address, interests } = req.body;

// 验证必需字段
if (!personalInfo || !address) {
return res.status(400).json({
success: false,
message: ‘缺少必需字段’
});
}

// 处理文件
const attachments = [];
if (req.files) {
for (const [fieldName, files] of Object.entries(req.files)) {
files.forEach(file => {
attachments.push({
originalName: file.originalname,
filename: file.filename,
path: file.path,
size: file.size
});
});
}
}

// 处理兴趣数组
const processedInterests = DataProcessor.processArray(
interests,
[‘reading’, ‘sports’, ‘music’, ‘travel’, ‘cooking’, ‘gaming’]
);

// 创建注册记录
const submission = new FormSubmission({
formType: ‘registration’,
submitter: {
name: DataProcessor.escapeHTML(personalInfo.name),
email: personalInfo.email.toLowerCase(),
phone: personalInfo.phone ? DataProcessor.normalizePhone(personalInfo.phone) : null,
age: personalInfo.age ? parseInt(personalInfo.age) : null
},
address: {
street: DataProcessor.escapeHTML(address.street),
city: DataProcessor.escapeHTML(address.city),
state: address.state || null,
zipCode: address.zipCode || null
},
interests: processedInterests,
attachments: attachments,
metadata: {
userAgent: req.get(‘User-Agent’),
ip: req.ip
}
});

await submission.save();

res.json({
success: true,
message: ‘注册表单提交成功’,
submissionId: submission._id,
attachments: attachments.length,
timestamp: submission.createdAt
});

} catch (error) {
// 清理已上传的文件
if (req.files) {
for (const files of Object.values(req.files)) {
files.forEach(file => {
try {
fs.unlinkSync(file.path);
} catch (e) {
console.error(‘清理文件失败:’, e);
}
});
}
}

console.error(‘注册表单处理错误:’, error);
res.status(500).json({
success: false,
message: ‘服务器内部错误’,
error: error.message
});
}
}

// 处理反馈表单
static async handleFeedbackForm(req, res) {
try {
const { rating, category, feedback, contactInfo } = req.body;

// 验证评分
if (!rating || rating < 1 || rating > 5) {
return res.status(400).json({
success: false,
message: ‘评分必须是1-5之间的数字’
});
}

// 创建反馈记录
const submission = new FormSubmission({
formType: ‘feedback’,
submitter: {
name: contactInfo?.name ? DataProcessor.escapeHTML(contactInfo.name) : ‘匿名用户’,
email: contactInfo?.email || null
},
message: DataProcessor.sanitizeHTML(feedback),
metadata: {
userAgent: req.get(‘User-Agent’),
ip: req.ip,
rating: parseInt(rating),
category: category
}
});

await submission.save();

res.json({
success: true,
message: ‘反馈已收到,感谢您的意见’,
submissionId: submission._id,
rating: rating
});

} catch (error) {
console.error(‘反馈处理错误:’, error);
res.status(500).json({
success: false,
message: ‘服务器内部错误’,
error: error.message
});
}
}

// 获取提交列表(管理后台用)
static async getSubmissions(req, res) {
try {
const { page = 1, limit = 10, formType, status } = req.query;

const query = {};
if (formType) query.formType = formType;
if (status) query[‘metadata.status’] = status;

const submissions = await FormSubmission.find(query)
.sort({ ‘metadata.submissionTime’: -1 })
.limit(limit * 1)
.skip((page – 1) * limit)
.select(‘-__v’);

const total = await FormSubmission.countDocuments(query);

res.json({
success: true,
data: submissions,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
});

} catch (error) {
console.error(‘获取提交列表错误:’, error);
res.status(500).json({
success: false,
message: ‘服务器内部错误’,
error: error.message
});
}
}

// 处理单个提交
static async processSubmission(req, res) {
try {
const { id } = req.params;
const { notes, status, processedBy } = req.body;

const submission = await FormSubmission.findByIdAndUpdate(
id,
{
‘metadata.status’: status,
‘processingResult’: {
processedAt: new Date(),
notes: notes,
processedBy: processedBy
}
},
{ new: true }
);

if (!submission) {
return res.status(404).json({
success: false,
message: ‘提交记录未找到’
});
}

res.json({
success: true,
message: ‘提交已处理’,
data: submission
});

} catch (error) {
console.error(‘处理提交错误:’, error);
res.status(500).json({
success: false,
message: ‘服务器内部错误’,
error: error.message
});
}
}
}

module.exports = FormController;
4.4 路由配置
// routes/formRoutes.js – 完整路由配置
const express = require(‘express’);
const router = express.Router();
const FormController = require(‘../controllers/formController’);
const upload = require(‘../middleware/upload’);
const { body, validationResult } = require(‘express-validator’);

// 联系表单路由
const contactValidation = [
body(‘personalInfo.name’).trim().isLength({ min: 2, max: 50 }).withMessage(‘姓名2-50字符’),
body(‘personalInfo.email’).isEmail().withMessage(‘邮箱格式错误’),
body(‘message’).trim().isLength({ min: 10, max: 1000 }).withMessage(‘消息10-1000字符’)
];

router.post(‘/contact’, contactValidation, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ success: false, errors: errors.array() });
}
FormController.handleContactForm(req, res);
});

// 注册表单路由
const registrationValidation = [
body(‘personalInfo.name’).trim().isLength({ min: 2, max: 50 }),
body(‘personalInfo.email’).isEmail(),
body(‘personalInfo.age’).optional().isInt({ min: 1, max: 120 }),
body(‘address.street’).trim().notEmpty(),
body(‘address.city’).trim().notEmpty(),
body(‘interests’).optional().isArray({ max: 5 })
];

router.post(‘/registration’,
upload.fields([
{ name: ‘avatar’, maxCount: 1 },
{ name: ‘documents’, maxCount: 3 }
]),
registrationValidation,
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
// 清理文件
if (req.files) {
Object.values(req.files).flat().forEach(file => {
try { fs.unlinkSync(file.path); } catch (e) {}
});
}
return res.status(400).json({ success: false, errors: errors.array() });
}
FormController.handleRegistrationForm(req, res);
}
);

// 反馈表单路由
const feedbackValidation = [
body(‘rating’).isInt({ min: 1, max: 5 }).withMessage(‘评分1-5’),
body(‘feedback’).trim().isLength({ min: 10, max: 500 }).withMessage(‘反馈10-500字符’)
];

router.post(‘/feedback’, feedbackValidation, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ success: false, errors: errors.array() });
}
FormController.handleFeedbackForm(req, res);
});

// 管理后台路由(需要认证)
router.get(‘/submissions’, FormController.getSubmissions);
router.put(‘/submissions/:id/process’, FormController.processSubmission);

module.exports = router;
4.5 主服务器文件整合
// server.js – 完整服务器配置
const express = require(‘express’);
const cors = require(‘cors’);
const helmet = require(‘helmet’);
const morgan = require(‘morgan’);
const connectDB = require(‘./config/database’);
const formRoutes = require(‘./routes/formRoutes’);
require(‘dotenv’).config();

const app = express();
const PORT = process.env.PORT || 3000;

// 连接数据库
connectDB();

// 基础中间件
app.use(helmet());
app.use(cors({
origin: process.env.CORS_ORIGIN || ‘*’,
credentials: true
}));
app.use(morgan(‘combined’));
app.use(express.json({ limit: ’10mb’ }));
app.use(express.urlencoded({ extended: true, limit: ’10mb’ }));

// 静态文件服务(用于文件下载)
app.use(‘/uploads’, express.static(‘uploads’));

// 健康检查
app.get(‘/health’, (req, res) => {
res.json({
status: ‘OK’,
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});

// API路由
app.use(‘/api/forms’, formRoutes);

// 404处理
app.use((req, res) => {
res.status(404).json({
success: false,
message: ‘API端点不存在’,
path: req.path
});
});

// 错误处理中间件
app.use((err, req, res, next) => {
console.error(‘错误:’, err);

// 清理可能的上传文件
if (req.files) {
Object.values(req.files).flat().forEach(file => {
try { fs.unlinkSync(file.path); } catch (e) {}
});
}

res.status(err.status || 500).json({
success: false,
message: err.message || ‘服务器内部错误’,
…(process.env.NODE_ENV === ‘development’ && { stack: err.stack })
});
});

// 优雅关闭
process.on(‘SIGTERM’, () => {
console.log(‘SIGTERM received, shutting down gracefully’);
server.close(() => {
console.log(‘Process terminated’);
process.exit(0);
});
});

const server = app.listen(PORT, () => {
console.log(`🚀 Server running on http://localhost:${PORT}`);
console.log(`📊 Health check: http://localhost:${PORT}/health`);
console.log(`📝 API docs: http://localhost:${PORT}/api/forms`);
});

module.exports = app;
第五部分:前端集成示例
5.1 现代前端框架集成(React)
// React表单组件示例
import React, { useState } from ‘react’;
import ‘./Form.css’;

function ContactForm() {
const [formData, setFormData] = useState({
personalInfo: { name: ”, email: ” },
message: ”
});
const [status, setStatus] = useState(‘idle’); // idle, submitting, success, error
const [error, setError] = useState(null);
const [submissionId, setSubmissionId] = useState(null);

const handleChange = (e) => {
const { name, value } = e.target;

if (name.includes(‘.’)) {
const [parent, child] = name.split(‘.’);
setFormData(prev => ({
…prev,
[parent]: { …prev[parent], [child]: value }
}));
} else {
setFormData(prev => ({ …prev, [name]: value }));
}
};

const handleSubmit = async (e) => {
e.preventDefault();
setStatus(‘submitting’);
setError(null);

try {
const response = await fetch(‘http://localhost:3000/api/forms/contact’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
},
body: JSON.stringify(formData)
});

const result = await response.json();

if (!response.ok) {
throw new Error(result.message || ‘提交失败’);
}

setStatus(‘success’);
setSubmissionId(result.submissionId);

// 重置表单
setFormData({
personalInfo: { name: ”, email: ” },
message: ”
});

// 3秒后重置状态
setTimeout(() => setStatus(‘idle’), 3000);

} catch (err) {
setStatus(‘error’);
setError(err.message);
}
};

return (

联系我们

{status === ‘success’ && (

✅ 提交成功!ID: {submissionId}

)}

{status === ‘error’ && (

❌ 错误: {error}

)}