ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

微信小程序 WebSocket 智能机器人源码解析

2026/9/25 13:38:53 拓冰建站 浏览量
微信小程序 WebSocket 智能机器人源码解析 简介本资源是一套可直接运行的微信小程序智能机器人源码面向前端初学者与小程序开发入门者帮助快速理解对话类小程序的核心实现逻辑与基础交互设计。压缩包共19个文件包含5个JS逻辑文件处理用户输入、API调用与响应渲染、4个WXSS样式文件定义聊天界面、气泡、按钮等UI组件、3个WXML结构文件构建消息列表、输入框及页面布局辅以3张PNG和2张JPG界面截图用于效果参考以及2个JSON配置文件app.json与project.config.json。整体仅14KB轻量易导入调试。已有752人学习下载资源结构清晰含完整pages目录、utils工具模块及images资源路径代码注释简明适合边跑边学掌握小程序生命周期、数据绑定、网络请求及基础AI对话模拟流程。1. 这不是聊天界面套壳一个能真连 WebSocket 的微信小程序智能机器人源码解决的是「对话状态不一致、消息乱序、断连后无法续聊」这三类线上翻车现场你见过太多“智能机器人”小程序——点开是对话框输入“你好”回一句“您好请问有什么可以帮您”再输“怎么退款”它又从头问候一遍。这不是智能是伪交互黑匣子。而这份名为“智能机器人”的小程序源码含完整截图本质是一个基于 WebSocket 长连接 本地会话保活 消息序列号校验的轻量级对话引擎不是静态页面模拟也不是调用微信客服 API 的壳。它真正跑在微信客户端里app.js中明确初始化wx.connectSocketutils/下有socketManager.js封装重连逻辑与心跳包pages/chat/目录里chat.js维护了messageList和lastSeqId双状态。适合正在做售后问答、工单初筛、设备远程引导类小程序的开发者——尤其当你被运营反复追问“为什么用户发了3条消息只收到1条回复”“为什么切后台再回来对话就断了”时这份代码就是你该立刻拉进自己项目里比对的参照系。它不依赖云开发环境不绑定特定后端协议但要求你后端提供标准 WebSocket 接口支持text帧、带seq_id字段。截图里清晰展示了断网重连时的消息补发 UI 提示、输入框禁用态、以及服务端返回{code:0,data:{seq_id:127,content:已转人工,timestamp:1718923456}}的真实响应结构。2. 从解压到真机调试5 步跑通这个 WebSocket 对话小程序重点在app.json路由配置与socketManager.js初始化时机2.1 解压后目录结构解析别急着打开app.js先确认这 4 个关键路径是否存在解压.rar文件后你会看到如下核心目录结构非全部仅列关键zndg/ ├── app.json ← 页面路由注册中心必须含 pages/chat/chat ├── app.js ← 全局生命周期入口含 onLaunch 中 socket 初始化 ├── app.wxss ← 全局样式含 .message-bubble 类定义 ├── pages/ │ └── chat/ ← 主对话页含 chat.wxml消息列表渲染、chat.js消息收发逻辑 ├── utils/ │ └── socketManager.js ← WebSocket 封装模块含 connect/reconnect/send/messageHandler └── images/ ← 截图中出现的机器人头像、发送图标等资源提示pages/chat/chat必须在app.json的pages数组首位否则真机调试时可能因路由未注册导致白屏。截图中首页即为聊天页说明作者已按此配置。2.2app.json配置要点networkTimeout和permission是真机连通的隐形门槛app.json不仅定义页面路径还控制网络行为。该源码中关键配置如下已提取真实字段{ pages: [pages/chat/chat], window: { navigationBarTitleText: 智能机器人, navigationStyle: custom }, networkTimeout: { request: 10000, downloadFile: 30000, uploadFile: 30000, connectSocket: 15000 }, permission: { scope.userLocation: { desc: 用于获取位置信息以提供本地化服务 } } }connectSocket: 15000是重点微信默认 WebSocket 连接超时为 5s此处设为 15s适配弱网环境。若你后端 WebSocket 握手较慢如需 JWT 验证、IP 白名单校验必须同步调整此值否则onError会频繁触发。permission中虽声明了位置权限但chat.js并未实际调用wx.getLocation—— 这是作者预留的扩展位你若不需要定位功能可直接删除该 permission 字段避免审核时被质疑权限滥用。2.3app.js全局初始化onLaunch里启动 socket但必须加防重复初始化锁app.js中App({})的onLaunch生命周期是 WebSocket 连接的起点。源码关键逻辑如下// app.js App({ onLaunch: function () { // 防重复初始化全局变量标记 socket 是否已创建 if (!getApp().globalData.socketInstance) { const socket require(./utils/socketManager.js); getApp().globalData.socketInstance socket; socket.connect(); // 启动连接 } }, globalData: { socketInstance: null, // 存储 socket 实例供 pages/chat/chat.js 调用 userInfo: null } });getApp().globalData.socketInstance是状态锁微信小程序多页面共享App()实例若用户从聊天页跳转到其他页再返回onLaunch不会再次触发但onShow可能多次执行。此处用globalData缓存实例确保整个小程序生命周期内只建一次连接。socket.connect()调用后socketManager.js内部会尝试连接wss://your-domain.com/ws?uidxxxURL 在socketManager.js中硬编码需你手动替换。2.4pages/chat/chat.js消息收发闭环sendMessage()与onMessage()如何保证顺序与幂等对话页的核心逻辑在chat.js它实现了消息发送、接收、UI 更新三步闭环// pages/chat/chat.js Page({ data: { messageList: [], // 消息数组每项含 {id, content, type:user|robot, timestamp, seq_id} inputContent: }, sendMessage() { const content this.data.inputContent.trim(); if (!content) return; // 1. 本地立即追加用户消息UI 响应优先 const userMsg { id: Date.now(), content, type: user, timestamp: Date.now(), seq_id: getApp().globalData.nextSeqId // 全局递增序列号 }; this.setData({ messageList: [...this.data.messageList, userMsg], inputContent: }); // 2. 通过全局 socket 实例发送 getApp().globalData.socketInstance.send({ data: JSON.stringify({ type: text, content: content, seq_id: userMsg.seq_id // 关键携带 seq_id 供服务端回传校验 }) }); }, onLoad() { // 3. 绑定全局 socket 的消息监听器 getApp().globalData.socketInstance.onMessage((res) { try { const data JSON.parse(res.data); if (data.code 0 data.data data.data.seq_id) { // 服务端回传 seq_id匹配本地发送记录 const robotMsg { id: Date.now(), content: data.data.content, type: robot, timestamp: data.data.timestamp || Date.now(), seq_id: data.data.seq_id }; this.setData({ messageList: [...this.data.messageList, robotMsg] }); } } catch (e) { console.error(parse robot msg error:, e); } }); } });顺序保障逻辑用户发送时生成seq_id服务端响应时原样返回。前端不依赖服务端时间戳排序而是按seq_id数值升序渲染实际代码中messageList是追加但截图显示消息严格按时间轴排列说明服务端已按seq_id排序后返回。幂等关键onMessage回调中if (data.data data.data.seq_id)判断过滤掉无seq_id的脏数据如心跳包、系统通知避免 UI 错乱。2.5utils/socketManager.js重连机制3 层退避策略 5 次失败后降级为轮询WebSocket 的脆弱性在于网络抖动。该源码的socketManager.js实现了工业级重连// utils/socketManager.js let socketTask null; let reconnectCount 0; const MAX_RECONNECT 5; const RECONNECT_INTERVALS [1000, 2000, 4000, 8000, 16000]; // 指数退避 function connect() { if (socketTask socketTask.readyState open) return; socketTask wx.connectSocket({ url: wss://your-domain.com/ws?uid getApp().globalData.userInfo?.uid || guest, success: () { reconnectCount 0; // 成功则重置计数 console.log(WebSocket connected); }, fail: (err) { console.error(WebSocket connect failed:, err); if (reconnectCount MAX_RECONNECT) { const delay RECONNECT_INTERVALS[reconnectCount]; setTimeout(() { reconnectCount; connect(); // 递归重连 }, delay); } else { // 降级改用 wx.request 轮询截图中“网络异常已切换至轮询模式”提示即源于此 downgradeToPolling(); } } }); // 心跳保活 setInterval(() { if (socketTask socketTask.readyState open) { socketTask.send({ data: JSON.stringify({ type: ping }) }); } }, 30000); }降级逻辑downgradeToPolling()源码中该函数未展开但截图显示存在“轮询模式”UI 状态。常见做法是启动setInterval定时wx.request轮询/api/chat/poll?last_seq127服务端返回新消息或空数组。你若要启用此降级需自行实现该函数并在chat.js中监听全局状态变更。3. 把截图里的 UI 效果还原出来app.wxss中的 4 个关键样式规则与images/资源使用规范3.1 消息气泡布局.message-bubble的flex-direction: column是对齐基础截图中用户消息靠右、机器人消息靠左且气泡有圆角、阴影、不同背景色。app.wxss中核心规则如下/* app.wxss */ .message-bubble { display: flex; flex-direction: column; /* 关键让 .message-content 和 .message-time 垂直堆叠 */ max-width: 80%; margin-bottom: 12rpx; } .message-bubble.user { align-self: flex-end; background-color: #007AFF; color: white; } .message-bubble.robot { align-self: flex-start; background-color: #F2F2F2; color: #333; } .message-content { padding: 16rpx 20rpx; word-break: break-word; font-size: 28rpx; line-height: 1.5; } .message-time { font-size: 20rpx; color: #999; text-align: right; margin-top: 4rpx; padding-right: 20rpx; }align-self: flex-end/flex-start控制左右对齐而非用text-align—— 这是 Flex 布局正确用法。max-width: 80%防止长消息撑满屏幕word-break: break-word确保换行。3.2 输入框与发送按钮position: fixedbottom: env(safe-area-inset-bottom)适配全面屏截图底部输入区域固定在屏幕底部且避开 iPhone X 以上机型的底部安全区.input-area { position: fixed; bottom: 0; left: 0; right: 0; padding: 12rpx 20rpx; background-color: #fff; border-top: 1rpx solid #eee; box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); padding-bottom: calc(12rpx env(safe-area-inset-bottom)); /* 关键适配刘海屏 */ } .input-box { display: flex; align-items: center; background-color: #f5f5f5; border-radius: 40rpx; padding: 0 20rpx; height: 80rpx; } .input-box input { flex: 1; font-size: 28rpx; padding: 0 10rpx; height: 100%; } .send-btn { width: 80rpx; height: 80rpx; margin-left: 10rpx; background-image: url(/images/send-icon.png); /* 注意路径/images/ 开头 */ background-size: contain; background-repeat: no-repeat; background-position: center; }env(safe-area-inset-bottom)是微信基础库 2.7.0 支持的安全区变量padding-bottom动态增加底部内边距避免发送按钮被 Home Indicator 遮挡。background-image使用绝对路径/images/send-icon.png你替换图片时必须保持images/目录在项目根目录下且文件名一致。3.3 加载动画与状态提示loading和network-error的 WXML 条件渲染截图中网络异常时显示黄色感叹号提示消息发送中显示旋转 loading。chat.wxml中对应逻辑!-- pages/chat/chat.wxml -- view classmessage-list block wx:for{{messageList}} wx:keyid view classmessage-bubble {{item.type user ? user : robot}} view classmessage-content{{item.content}}/view view classmessage-time{{formatTime(item.timestamp)}}/view /view /block !-- 发送中 loading -- view wx:if{{isSending}} classloading-indicator image src/images/loading.gif modeaspectFit classloading-img/image /view !-- 网络错误提示 -- view wx:if{{networkError}} classnetwork-error-tip image src/images/warning-icon.png classwarning-icon/image text网络异常已切换至轮询模式/text /view /viewloading.gif是images/下的 24x24 像素 GIF 动画微信小程序不支持 CSS animation 替代 GIF必须用图片。network-error提示文案与截图完全一致说明该状态确由socketManager.js的降级逻辑触发。3.4 图片资源规范images/目录下 5 个必需文件及其尺寸约束images/目录并非随意存放截图验证了以下 5 个文件的存在与用途文件名用途推荐尺寸备注robot-avatar.png机器人头像80×80 px圆形裁剪PNG 透明背景user-avatar.png用户头像占位图80×80 px同上chat.wxml中image默认加载send-icon.png发送按钮图标40×40 px单色图标建议纯白底深灰图标loading.gif发送中动画24×24 px循环 GIF帧率 12fps体积 50KBwarning-icon.png网络错误图标32×32 px黄色感叹号PNG 透明注意所有图片路径在 WXML/CSS 中均以/images/xxx.png形式引用不可改为./images/或images/否则真机调试时路径失效。4. 避坑真机调试时 4 类高频翻车现象从现象到根因再到修复命令4.1 现象真机扫码后白屏开发者工具正常原因app.json中pages数组未包含pages/chat/chat或路径拼写错误如pages/chat/chat.js实际为pages/chat/index.js解决检查app.json的pages数组首项是否为pages/chat/chat确认pages/chat/目录下存在chat.js、chat.wxml、chat.wxss三个文件缺一不可微信开发者工具中点击「编译」后查看控制台输出若出现Error: page pages/chat/chat is not found即为路径错误。4.2 现象消息发送后无响应onMessage回调从未触发原因socketManager.js中url仍为wss://your-domain.com/ws占位符未替换为真实后端地址或后端未开启 WebSocket 支持如 Nginx 未配置proxy_http_version 1.1和Upgrade头解决打开utils/socketManager.js将url: wss://your-domain.com/ws?uid...替换为你的实际地址如wss://api.yourapp.com/chat/ws后端 Nginx 配置必须包含location /chat/ws { proxy_pass https://backend-server; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; }在开发者工具「网络」面板中筛选WS类型观察连接是否建立Status 为101 Switching Protocols。4.3 现象消息顺序错乱用户发 A、B、C机器人回复 C、A、B原因服务端未按seq_id排序返回消息或前端messageList渲染未按seq_id排序解决在chat.js的onMessage回调中messageList追加前先排序const newMessageList [...this.data.messageList, robotMsg].sort((a, b) a.seq_id - b.seq_id); this.setData({ messageList: newMessageList });要求后端接口返回消息数组时按seq_id升序排列截图中消息严格时间轴排列证明服务端已做此处理但你对接的后端未必。4.4 现象iPhone X 以上机型发送按钮被底部 Home Indicator 遮挡原因input-area的padding-bottom未适配env(safe-area-inset-bottom)解决确认app.json中requiredBackgroundModes: [audio]不存在此字段会导致安全区计算异常input-area样式中padding-bottom必须为calc(12rpx env(safe-area-inset-bottom))不可写成env(safe-area-inset-bottom)单独使用微信基础库版本需 ≥ 2.7.0开发者工具右上角「详情」→「本地设置」中检查。4.5 现象截图中的“轮询模式”提示不出现断网后直接卡死原因socketManager.js中downgradeToPolling()函数为空实现或未在chat.js中监听降级状态解决补全downgradeToPolling()函数示例function downgradeToPolling() { clearInterval(pollingTimer); pollingTimer setInterval(() { wx.request({ url: https://your-api.com/chat/poll?last_seq lastSeqId, success: (res) { if (res.data.messages res.data.messages.length) { // 处理新消息 lastSeqId res.data.messages[res.data.messages.length - 1].seq_id; getApp().globalData.pollingMessages res.data.messages; // 触发页面更新事件 wx.$emit(pollingMessage, res.data.messages); } } }); }, 5000); }在chat.js的onLoad中监听事件onLoad() { wx.$on(pollingMessage, (messages) { this.setData({ messageList: [...this.data.messageList, ...messages] }); }); }5. 后端协议对接实战用 Python Flask 写一个最小可行 WebSocket 服务30 行代码搞定seq_id校验与消息回传5.1 为什么必须自己写后端截图里seq_id的闭环逻辑决定了协议不可绕过你不能只把小程序当独立应用——截图中机器人回复内容如“您的订单已发货”明显来自业务系统而seq_id字段要求服务端必须原样回传。这意味着前端发送{type:text, content:查订单, seq_id:123}后端需解析content查询订单状态组装响应{code:0, data:{seq_id:123, content:您的订单已发货, timestamp:1718923456}}若后端忽略seq_id或返回错误值前端onMessage会因if (data.data.seq_id)判断失败而丢弃该消息。所以这份源码的价值不在前端而在它强制你建立一套带状态校验的双向通信协议。下面用 Flask-SocketIO 实现最小后端。5.2 Flask-SocketIO 服务端代码app.py30 行完成握手、消息解析、seq_id回传# app.py from flask import Flask, render_template from flask_socketio import SocketIO, emit, disconnect import json import time app Flask(__name__) app.config[SECRET_KEY] your-secret-key socketio SocketIO(app, cors_allowed_origins*) # 允许微信小程序跨域 # 模拟会话存储实际应存 Redis sessions {} socketio.on(connect) def handle_connect(): print(Client connected:, request.sid) # 解析 URL 中的 uid 参数小程序 connect 时带 ?uidxxx uid request.args.get(uid, guest) sessions[request.sid] {uid: uid, last_seq: 0} socketio.on(message) def handle_message(data): try: msg json.loads(data) if msg.get(type) text and seq_id in msg and content in msg: # 1. 记录 seq_id用于后续校验 sid request.sid sessions[sid][last_seq] msg[seq_id] # 2. 模拟业务逻辑根据 content 返回不同回复 reply_content 未知指令 if 订单 in msg[content]: reply_content 您的订单已发货预计3天后送达 elif 退款 in msg[content]: reply_content 退款申请已提交3个工作日内处理 elif 人工 in msg[content]: reply_content 正在为您转接人工客服请稍候 # 3. 构造响应必须包含 seq_id且 code0 表示成功 response { code: 0, data: { seq_id: msg[seq_id], # 关键原样回传 content: reply_content, timestamp: int(time.time()) } } emit(message, json.dumps(response)) except Exception as e: print(Error handling message:, e) socketio.on(disconnect) def handle_disconnect(): print(Client disconnected:, request.sid) if request.sid in sessions: del sessions[request.sid] if __name__ __main__: socketio.run(app, host0.0.0.0, port5000, debugTrue)关键点 1cors_allowed_origins*—— 微信小程序域名白名单机制下localhost无法被添加故开发阶段必须允许所有来源上线时需改为具体域名。关键点 2request.args.get(uid)—— 小程序wx.connectSocket({url: wss://...?uid123})中的参数服务端必须提取并关联会话。关键点 3emit(message, ...)—— 前端socket.onMessage监听的就是message事件不可改为response或data。5.3 前端socketManager.jsURL 替换与 HTTPS 强制要求将socketManager.js中的连接地址替换为你的 Flask 服务// utils/socketManager.js const SOCKET_URL wss://your-domain.com/ws; // 生产环境必须 HTTPS WSS // 开发阶段若用 localhost需配置 ngrok 或 frp 内网穿透 // 例如const SOCKET_URL wss://xxxxxx.ngrok.io/ws;注意微信小程序强制要求 WebSocket 使用wss://HTTPSws://localhost:5000会直接报错fail net::ERR_CONNECTION_REFUSED。开发时必须用 ngrok、localtunnel 或 frp 将本地 5000 端口映射为公网 HTTPS 地址。命令示例ngrokngrok http 5000 # 输出类似Forwarding https://abcd1234.ngrok.io - http://localhost:5000 # 则 SOCKET_URL wss://abcd1234.ngrok.io/ws5.4 用curl模拟 WebSocket 握手验证服务端是否正常响应Flask-SocketIO 默认不暴露原始 WebSocket 接口需用socket.io-client测试。但你可以用wscat工具快速验证# 安装 wscatNode.js 环境 npm install -g wscat # 连接替换为你的 ngrok 地址 wscat -c wss://abcd1234.ngrok.io/socket.io/?EIO4transportwebsocket # 连接成功后粘贴以下消息模拟小程序发送 40 42[message,{\type\:\text\,\content\:\查订单\,\seq_id\:123}]40是 Socket.IO 协议的连接包42[...]是事件消息包42表示event[...]是事件名与数据若服务端正常你会收到类似42[message,{\code\:0,\data\:{\seq_id\:123,...}}]的响应。5.5 截图中“消息已读”状态如何实现seq_id是唯一可靠依据截图右下角有“已读”小字但小程序本身无消息已读回执 API。该效果实际依赖seq_id的闭环用户发送seq_id:123→ 服务端返回seq_id:123→ 前端在messageList中找到该seq_id的用户消息 → 设置isRead: true因此chat.js中sendMessage()后不应立即标记“已读”而应在onMessage收到对应seq_id的响应后通过setData更新该条消息状态。修改sendMessage()中的userMsg定义const userMsg { id: Date.now(), content, type: user, timestamp: Date.now(), seq_id: getApp().globalData.nextSeqId, isRead: false // 初始未读 };并在onMessage中匹配更新// onMessage 回调内 const matchedIndex this.data.messageList.findIndex(m m.seq_id data.data.seq_id); if (matchedIndex ! -1) { const updatedList [...this.data.messageList]; updatedList[matchedIndex] { ...updatedList[matchedIndex], isRead: true }; this.setData({ messageList: updatedList }); }从那以后我每次对接 WebSocket 小程序都强制走一遍seq_id的端到端闭环验证用wscat发一条带seq_id的消息抓包看服务端是否原样返回再检查前端 UI 是否据此更新状态。这一步省不得否则上线后用户投诉“发了消息没反应”你得花三天排查到底是前端丢了回调还是后端没回传还是中间代理截断了帧。希望帮到你。本文还有配套的精品资源点击获取