WeLive:架構(gòu)、部署與二次開發(fā)實戰(zhàn)指南)
簡介WeLive是一款采用PHP開發(fā)的開源在線客服系統(tǒng)基于WebSocket全雙工通信實現(xiàn)請求與推送兼顧Web端和移動端內(nèi)置AI自動回復(fù)、5種配色、中英文自動切換且客服坐席無數(shù)量限制適合需要自主搭建網(wǎng)站客服體系的PHP開發(fā)者或中小企業(yè)。資源包為5.9.0版本共287個文件含56個PHP源碼文件、127張PNG界面圖、21個MP3提示音以及JS/CSS腳本等整體僅1.6MB源碼結(jié)構(gòu)清晰便于本地部署和二次定制。已有330人學(xué)習(xí)包內(nèi)附更新說明可幫助快速掌握新增的訪客提示音選擇、單雙窗口切換、離線訪客關(guān)閉、上傳權(quán)限控制等功能同時可結(jié)合后臺配置實現(xiàn)AI機器人無人值守減少人工成本??傮w而言這份資源既適合想低成本自建客服系統(tǒng)的技術(shù)團隊也適合希望學(xué)習(xí)WebSocket客服系統(tǒng)開發(fā)流程的PHP學(xué)習(xí)者收藏參考。1. WeLive是什么以及為什么還需要一個PHP客服系統(tǒng)先直接回答最實際的問題WeLive是一套基于ThinkPHP 3.2.3框架開發(fā)的免費開源PHP在線客服系統(tǒng)服務(wù)端語言是PHP前端和管理后臺都是標準的Web頁面部署到自己的服務(wù)器就能用。它解決的核心問題很明確——你的網(wǎng)站、App、小程序里需要掛一個能夠?qū)崟r聊天、自動分配、留檔查詢的客服窗口但不想為這件事每年支付幾千上萬的SaaS訂閱費也不想被第三方平臺掐住數(shù)據(jù)接口和聊天記錄?,F(xiàn)在市面上開源的客服系統(tǒng)其實不少Go寫的、Java寫的都有但PHP版本仍然有大量剛需。原因很實際大量中小型網(wǎng)站、企業(yè)官網(wǎng)、個人博客跑在虛擬主機或低配云服務(wù)器上環(huán)境就是LNMP或者LAMP讓你為了一個客服系統(tǒng)去專門裝Java環(huán)境或者Go環(huán)境運維成本直接翻倍。WeLive這種純PHP方案的優(yōu)勢就在這兒——只要服務(wù)器能跑WordPress基本就能跑WeLive部署門檻幾乎為零。這個系統(tǒng)適合誰來用我覺得有三類人特別對口。第一類是PHP開發(fā)者和外包接單者接到企業(yè)官網(wǎng)需要帶客服功能的需求直接部署一套WeLive再改改皮膚就能交付省掉從零寫聊天功能的重復(fù)勞動。第二類是中小企業(yè)站長不想把訪客數(shù)據(jù)、聊天記錄放在別人的SaaS平臺上需要數(shù)據(jù)完全自控。第三類是技術(shù)愛好者想研究一個完整的PHP客服系統(tǒng)的代碼結(jié)構(gòu)學(xué)習(xí)ThinkPHP 3.2.3的項目組織方式WeLive的代碼量適中適合通讀。我自己實際部署過的感受是這套系統(tǒng)的定位很務(wù)實不玩花活。它的功能覆蓋了在線客服系統(tǒng)最核心的幾條鏈路訪客端對話窗口、客服端工作臺、會話分配機制、消息持久化存儲、歷史記錄查詢、常用回復(fù)話術(shù)。沒有復(fù)雜的微服務(wù)、沒有消息隊列、沒有容器編排就是老老實實的PHP MySQL 前端輪詢/推送反而讓它在低配服務(wù)器上跑得很穩(wěn)。下面我把整個系統(tǒng)的架構(gòu)邏輯、部署細節(jié)和二次開發(fā)要點一條條展開講。2. 核心功能拆解與技術(shù)實現(xiàn)方案2.1 訪客端到客服端的完整消息鏈路在線客服系統(tǒng)最核心的鏈路就是消息從訪客瀏覽器發(fā)到客服工作臺再由客服回復(fù)回訪客瀏覽器。WeLive在這條鏈路上采用的是典型的PHP方案訪客端通過前端Ajax輪詢或者長輪詢方式拉取新消息客服端同樣通過輪詢從服務(wù)端獲取新的訪客消息。這里的“輪詢”不是每秒發(fā)一次請求的低效做法而是設(shè)置了合理的時間間隔結(jié)合會話心跳機制在保證消息實時性和服務(wù)器負載之間取平衡。具體的消息表設(shè)計核心是session_message這類消息表包含字段消息ID、會話ID、發(fā)送者類型訪客/客服、發(fā)送者ID、消息類型文本/圖片/系統(tǒng)消息、消息內(nèi)容、創(chuàng)建時間。寫入消息時通過事務(wù)保證會話維度的數(shù)據(jù)一致性。這里有個容易踩的坑在線客服系統(tǒng)的消息并發(fā)量雖然遠低于社交軟件但訪客端和客服端同時操作同一條會話時容易出現(xiàn)重復(fù)插入或者會話狀態(tài)錯亂的問題所以寫入操作必須帶會話級鎖或者樂觀鎖控制。我補充一下為什么選擇輪詢而不是WebSocket。WeLive基于ThinkPHP 3.2.3這個框架版本的PHP原生環(huán)境跑WebSocket需要額外維護常駐進程對于虛擬主機用戶來說根本無法實現(xiàn)。輪詢方式雖然實時性不如WebSocket但勝在兼容性極強任何能跑PHP的環(huán)境都能跑起來。實際使用中把輪詢間隔設(shè)置在2到3秒訪客感知不到明顯延遲服務(wù)器負載也完全可控。2.2 客服工作臺與多客服分配機制客服端工作臺是WeLive里功能最密集的部分。登錄后可以看到當(dāng)前在線訪客列表、進行中的會話、歷史會話記錄、訪客詳情IP、來源頁面、瀏覽時間等。多客服分配這塊系統(tǒng)默認實現(xiàn)的是輪流分配或手動搶接兩種模式。輪流分配模式下系統(tǒng)維護一個客服隊列新訪客發(fā)起咨詢時自動分配給隊列中當(dāng)前空閑且在線狀態(tài)為“可接待”的客服。分配算法的實現(xiàn)在服務(wù)端是一個簡單的取?;蛑羔樢苿舆壿嫷⒁庖粋€細節(jié)客服離線或者會話數(shù)已滿時必須從分配池中剔除否則會出現(xiàn)訪客消息分配給一個根本不在線的客服導(dǎo)致訪客長時間無人回復(fù)。我在排查一些部署案例時發(fā)現(xiàn)很多人反饋“訪客發(fā)了消息沒人接”八成是分配池的狀態(tài)同步邏輯沒有處理好。WeLive在這一塊的做法是維護客服狀態(tài)表通過心跳機制更新客服的在線狀態(tài)、忙碌狀態(tài)和當(dāng)前接待數(shù)每次分配前先篩一遍可用客服列表。2.3 消息記錄、統(tǒng)計報表與數(shù)據(jù)管理消息記錄是客服系統(tǒng)價值密度最高的數(shù)據(jù)資產(chǎn)。WeLive提供了按時間范圍、按客服、按訪客維度篩選歷史消息的能力支持導(dǎo)出。這個功能對團隊管理者特別有用——可以復(fù)盤客服響應(yīng)時長、服務(wù)質(zhì)量也能在發(fā)生糾紛時調(diào)取聊天記錄作為憑證。統(tǒng)計報表方面系統(tǒng)核心關(guān)注幾個指標會話總數(shù)、平均響應(yīng)時長、平均會話時長、消息總數(shù)、客服接待量排行。這里的實現(xiàn)方式是定時腳本或每次會話關(guān)閉時更新統(tǒng)計表避免實時聚合大表導(dǎo)致性能問題。我建議在實際使用中定期把統(tǒng)計結(jié)果導(dǎo)出備份因為MySQL中的數(shù)據(jù)表如果長時間運行不清理會話表和消息表會迅速膨脹影響查詢性能。3. 環(huán)境準備與部署實操全流程3.1 部署環(huán)境要求與參數(shù)選擇WeLive依賴的PHP版本和ThinkPHP框架直接相關(guān)。ThinkPHP 3.2.3對PHP版本的要求是5.3以上但實測在PHP 5.6和PHP 7.0下運行最穩(wěn)定PHP 7.2以上部分老代碼會出現(xiàn)兼容性警告尤其是mysql擴展替換為mysqli或PDO的過程中可能暴露問題。數(shù)據(jù)庫要求MySQL 5.5及以上建議5.7字符集統(tǒng)一用utf8mb4否則訪客消息里如果帶了emoji表情存入數(shù)據(jù)庫時會報“Incorrect string value”錯誤。Web服務(wù)器Apache或Nginx均可Nginx需要額外配置偽靜態(tài)規(guī)則把請求重寫到入口文件。操作系統(tǒng)Linux優(yōu)先Windows服務(wù)器用phpstudy或WAMP環(huán)境也能跑但生產(chǎn)環(huán)境還是建議Linux。下面是部署前的關(guān)鍵參數(shù)建議表參數(shù)項建議配置說明PHP版本5.6 / 7.0兼容性最佳避免過高版本MySQL版本5.7支持utf8mb4性能穩(wěn)定Web服務(wù)器Nginx / ApacheNginx需配偽靜態(tài)規(guī)則PHP擴展pdo_mysql, curl, mbstring必須開啟缺一不可內(nèi)存1GB以上低配512MB也能跑但會吃力輪詢間隔2~3秒在config中配置3.2 從下載到上線完整安裝步驟第一步是下載源碼。從WeLive的官方開源倉庫獲取最新版本代碼解壓到網(wǎng)站根目錄。這里注意一個細節(jié)不要把源碼直接解壓到服務(wù)器現(xiàn)有網(wǎng)站的根目錄建議用獨立子目錄部署例如/wechat/或/kefu/避免入口文件和現(xiàn)有路由規(guī)則沖突。第二步是配置數(shù)據(jù)庫。創(chuàng)建數(shù)據(jù)庫并導(dǎo)入項目根目錄下的SQL文件我使用命令行導(dǎo)入mysql -u root -p -e CREATE DATABASE welive DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p welive welive.sql導(dǎo)入完成后修改數(shù)據(jù)庫配置文件。ThinkPHP 3.2.3的數(shù)據(jù)庫配置在Application/Common/Conf/config.php中重點修改數(shù)據(jù)庫主機、庫名、用戶名、密碼。第三步是配置Web服務(wù)器。以Nginx為例需要在server塊中添加偽靜態(tài)規(guī)則location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } }Apache則需要在.htaccess中配置對應(yīng)的RewriteRule。配置完成后訪問安裝向?qū)У刂钒凑仗崾就瓿砂惭b。安裝向?qū)z查PHP擴展是否齊全、目錄是否可寫綠勾全亮后即可進入系統(tǒng)。第四步是配置訪客端接入。WeLive提供了一段JavaScript代碼將代碼嵌入到你的網(wǎng)站頁面底部前端就會渲染出客服對話浮窗。這段代碼的核心作用是拉取訪客標識通常用cookie或localStorage生成唯一ID然后調(diào)用后端接口建立會話、獲取歡迎語、建立消息輪詢。3.3 訪客端嵌入代碼的實操寫法嵌入代碼的正確寫法直接影響訪客識別和會話建立。下面是我整理的最小可用嵌入模板script typetext/javascript (function() { var welive document.createElement(script); welive.type text/javascript; welive.async true; welive.src https://yourdomain.com/index.php?gVisitmIndexawidget; var s document.getElementsByTagName(script)[0]; s.parentNode.insertBefore(welive, s); })(); /script這里的yourdomain.com替換為你的WeLive部署域名。腳本加載后會動態(tài)創(chuàng)建對話浮窗并在訪客點擊浮窗時發(fā)起會話請求。如果發(fā)現(xiàn)訪客打開網(wǎng)站后看不到浮窗最常見的原因是腳本加載的跨域問題——頁面域名和WeLive部署域名不是同一個域名需要在后端配置允許跨域的頭信息或者在嵌入頁面通過反向代理把客服路徑代理到同域下。4. 常見問題與排查技巧實錄4.1 消息發(fā)不出去的排查思路我遇到過幾十次“訪客發(fā)消息收不到”的反饋這類問題90%集中在會話狀態(tài)異常上。先看服務(wù)端日志確認請求有沒有到達PHP層。沒有到達就是網(wǎng)絡(luò)層問題——檢查Nginx配置中是否有對index.php的訪問限制或者防火墻是否攔截了POST請求。請求到達PHP層但仍發(fā)不出去打開瀏覽器開發(fā)者工具看Network面板重點看接口返回的JSON狀態(tài)碼。一個典型的坑是ThinkPHP的URL模式配置。如果你開啟了REWRITE模式但服務(wù)器偽靜態(tài)沒配好接口路徑會全部404。解決方法是把URL_MODEL修改為兼容模式即URL_MODEL 2讓URL帶上index.php入口標識繞過偽靜態(tài)依賴。消息已入庫但客服端看不到則是輪詢邏輯問題。檢查客服工作臺的消息輪詢請求是否攜帶了正確的客服登錄態(tài)session如果客服長時間不操作導(dǎo)致session過期輪詢接口會返回未登錄前端沒有做自動跳轉(zhuǎn)登錄頁的處理看起來就像“系統(tǒng)卡住了”。4.2 數(shù)據(jù)庫連接數(shù)與慢查詢優(yōu)化WeLive部署到有一定訪客量的站點后最容易暴露的問題是數(shù)據(jù)庫連接數(shù)被打滿。排查方法SHOW PROCESSLIST; SHOW VARIABLES LIKE max_connections;當(dāng)看到大量Sleep狀態(tài)的連接堆積時說明PHP進程持有的數(shù)據(jù)庫連接沒有及時釋放。ThinkPHP 3.2.3默認的數(shù)據(jù)庫連接配置里可以在config.php中開啟連接池或調(diào)整連接超時參數(shù)但我實測最有效的辦法是給MySQL增加wait_timeout和interactive_timeout的合理值比如設(shè)置為60秒這樣空閑連接能快速回收。慢查詢方面消息表的數(shù)據(jù)量到達幾十萬條后不帶索引的查詢會明顯拖慢客服端打開會話記錄的速度。建議在session_message表的sender_id和create_time字段上建立聯(lián)合索引在session表的status和last_message_time字段上建立索引。這是低成本高收益的優(yōu)化手段。4.3 多域名部署時的Cookie與Session問題我在實際項目里遇到過一個很有意思的問題同一套WeLive同時嵌入了三個不同域名的網(wǎng)站訪客在A網(wǎng)站發(fā)起咨詢后跳到B網(wǎng)站又發(fā)起一次咨詢結(jié)果被系統(tǒng)判定為同一個訪客歷史消息串了。原因是訪客標識依賴Cookie而Cookie是按域名隔離的但我的自定義邏輯里用了固定的客戶端ID生成規(guī)則導(dǎo)致不同域名的Cookie被瀏覽器隔離后生成的訪客ID重復(fù)了。正確的做法是在生成訪客唯一ID時疊加一個隨機因子或者直接使用uniqid()配合更多的熵源。將訪客的標識與具體來路域名綁定避免跨域串號。5. 二次開發(fā)的幾個方向和實用建議5.1 消息推送升級從輪詢到WebSocket如果你覺得輪詢方式不夠極致想升級到WebSocket方案可以基于Workerman或Swoole做改造。核心思路是保留現(xiàn)有的消息存儲邏輯在消息寫入后觸發(fā)一個異步事件通過WebSocket服務(wù)推送給在線客服。這樣改造的工作量集中在前端消息接收層和增加一個常駐進程服務(wù)不需要動數(shù)據(jù)庫結(jié)構(gòu)。但我的建議是如果你的站點日活訪客在幾千這個量級保持輪詢完全夠用沒必要增加運維復(fù)雜度。升級WebSocket意味著服務(wù)器需要常駐內(nèi)存進程虛擬主機將不再支持部署門檻會提高一個檔次。5.2 與主流CMS和電商系統(tǒng)的對接WeLive常見的二次開發(fā)方向是和企業(yè)已有的用戶體系打通。比如在ThinkPHP框架內(nèi)部增加一個用戶身份映射接口當(dāng)已登錄用戶發(fā)起咨詢時自動把用戶昵稱、手機號、歷史訂單信息帶入會話信息中。這個功能在電商場景下價值很大——客服一接會話就能看到來咨詢的人是誰、買了什么、想退什么。對接方式可以通過在WeLive的會話創(chuàng)建接口中增加一個擴展字段前端嵌入時從業(yè)務(wù)系統(tǒng)的全局變量中讀取用戶信息拼裝到初始化參數(shù)里后端接收后寫入session_info表。5.3 數(shù)據(jù)遷移與備份策略在線客服系統(tǒng)的數(shù)據(jù)價值很高必須做好備份。我把備份策略拆成兩個層面數(shù)據(jù)庫層面每天凌晨自動導(dǎo)出全量SQL文件保留最近30天文件層面主要是上傳的圖片等附件做好異地備份。恢復(fù)時要注意數(shù)據(jù)表的自增ID如果被重置過會出現(xiàn)會話和消息無法對應(yīng)的問題所以SQL文件的導(dǎo)入導(dǎo)出不要用--no-create-info參數(shù)必須包含完整的表結(jié)構(gòu)和數(shù)據(jù)。我自己部署過多個PHP客服系統(tǒng)WeLive給我的整體印象是作為一套ThinkPHP 3.2.3時代的產(chǎn)物它的代碼結(jié)構(gòu)清晰、部署簡單、功能足夠?qū)嵱锰貏e適合中小型項目。如果你正在找一套能快速落地、方便改代碼的PHP在線客服方案把WeLive拉下來跑一遍大概率不會讓你失望。最后分享一個小技巧部署完成后建議在后臺把默認的管理員密碼改掉再關(guān)掉調(diào)試模式很多安全風(fēng)險都是因為這兩步偷懶導(dǎo)致的。本文還有配套的精品資源點擊獲取