
本文介绍如何通过 socket.io 发送结构化的多字段订单数据(如订单号、商品列表、状态等),结合 json 协议设计可扩展的实时通信格式,并安全存入 sql 数据库。
本文介绍如何通过 socket.io 发送结构化的多字段订单数据(如订单号、商品列表、状态等),结合 json 协议设计可扩展的实时通信格式,并安全存入 sql 数据库。
在快餐管理系统中,前端需将用户点击的多个菜品、数量、备注等信息一次性提交至主服务端,并同步显示在中央大屏(如麦当劳式订单看板)。此时,不推荐使用隐藏输入框拼接字符串——这种方式难以维护、易出错、无法表达嵌套结构(如“汉堡×2 + 可乐×1”),且缺乏类型校验与扩展性。
✅ 正确做法是:定义统一的 JSON 消息协议,通过 Socket.IO emit 一次性发送完整订单对象。
1. 定义标准化订单消息结构
建议采用语义清晰、可扩展的 JSON 格式,包含必要元信息:
{
"type": "order_submit",
"order_id": "ORD-2024-00872",
"timestamp": "2024-06-15T14:22:35Z",
"items": [
{ "id": "burger-001", "name": "巨无霸", "quantity": 2, "price": 25.0 },
{ "id": "drink-003", "name": "中杯可乐", "quantity": 1, "price": 12.0 }
],
"status": "pending",
"table_no": "A12",
"notes": "不要洋葱"
}
✅
type字段用于服务端路由(如区分order_submit/order_update/kitchen_ack);
✅items是数组,天然支持任意数量商品;
✅ 所有字段均为强语义命名,便于前后端协作与数据库映射。
2. 前端发送示例(JavaScript + Socket.IO Client)
// 初始化 socket(假设已连接)
const socket = io('http://localhost:5000');
// 构建订单对象(可由按钮点击动态累积)
let currentOrder = {
items: [],
table_no: 'A12',
notes: ''
};
// 按钮点击添加商品(ID 绑定商品配置)
document.querySelectorAll('.food-btn').forEach(btn => {
btn.addEventListener('click', () => {
const item = {
id: btn.dataset.id,
name: btn.dataset.name,
quantity: parseInt(btn.dataset.qty) || 1,
price: parseFloat(btn.dataset.price)
};
currentOrder.items.push(item);
});
});
// 提交完整订单
document.getElementById('submit-order').addEventListener('click', () => {
const orderPayload = {
type: 'order_submit',
order_id: `ORD-${new Date().getFullYear()}-${String(Date.now()).slice(-5)}`,
timestamp: new Date().toISOString(),
...currentOrder,
status: 'pending'
};
// 一次性发出结构化数据
socket.emit('order_event', orderPayload);
// 清空本地草稿(可选)
currentOrder.items = [];
});
3. 后端接收与持久化(Python + Flask-SocketIO + SQLAlchemy)
from flask_socketio import SocketIO
from sqlalchemy import create_engine
from models import Order, OrderItem # 假设已定义 ORM 模型
socketio = SocketIO(app, cors_allowed_origins="*")
@socketio.on('order_event')
def handle_order_event(data):
if data.get('type') != 'order_submit':
return
# 生成唯一订单号(生产环境建议用 UUID 或 DB 自增+前缀)
order = Order(
order_id=data['order_id'],
table_no=data['table_no'],
status=data['status'],
notes=data.get('notes', ''),
created_at=data['timestamp']
)
# 关联商品项
for item in data['items']:
order.items.append(OrderItem(
product_id=item['id'],
name=item['name'],
quantity=item['quantity'],
price=item['price']
))
db.session.add(order)
db.session.commit()
# 广播至所有监听订单的客户端(如大屏)
socketio.emit('new_order', {
'order_id': order.order_id,
'items_count': len(order.items),
'status': order.status
})
⚠️ 关键注意事项
- 不要在前端拼接字符串或依赖 DOM 隐藏字段:易被篡改、无类型约束、难以调试;
-
始终校验
type字段:防止非法消息触发错误逻辑; -
时间戳由前端生成时需校准服务器时间:建议后端统一写入
created_at; -
订单号生成需保证全局唯一且可排序:避免使用纯随机数,推荐
时间戳+业务前缀+序列号; - 敏感操作(如支付、取消)应增加权限校验与幂等处理。
通过该方案,你不仅实现了多字段订单的一次性可靠传输,还为后续扩展(如实时厨房状态更新、多终端协同、订单溯源)奠定了坚实基础。











