李建華 夏 汛 羅明全
(瀘州職業(yè)技術學院信息工程系 四川 瀘州 646600)
隨著信息技術的發(fā)展,互聯(lián)網(wǎng)在給我們提供豐富信息的同時也給我們生活帶來了巨大改變,信息時代下人們已經離不開互聯(lián)網(wǎng)。與此同時,類似于QQ、微信、微博等社交網(wǎng)絡應用充斥著整個互聯(lián)網(wǎng),其中以微信應用最為典型。微信公眾號是微信公眾平臺的簡稱,利用微信公眾號可以進行自媒體活動,用戶可在微信平臺上和目標受眾用戶用語言、文字、視頻等多種方式進行交流,形成一種微營銷方式,使得微信公眾號在消息互動的同時也在傳遞著商業(yè)價值。
據(jù)《2017 年微信經濟數(shù)據(jù)報告》可知,截至2017年底微信公眾號已超過1 000萬個[1],微信公眾號已經成為了公司對外宣傳的標配。公司通過微信公眾號向受眾用戶及時推送消息和業(yè)務,極大地拉近了企業(yè)和用戶之間的距離;用戶通過關注企業(yè)微信公眾號,可以充分了解企業(yè)業(yè)務動向和產品文化。
微信公眾號基礎平臺已經為用戶提供了一些基本的功能,如文章推送、粉絲管理等。但是對于部分特殊功能,則需要開發(fā)者自行擴展。微信公眾號平臺已將自帶的資源服務封裝成接口,這就使得二次開發(fā)成為可能。同時隨著粉絲數(shù)量越來越龐大,一些類似抽獎、搶紅包等高并發(fā)功能的二次開發(fā)成為必要。
本文以某企業(yè)為例,為了有效地對外宣傳其企業(yè)文化,擴大市場知名度,需要每位員工發(fā)現(xiàn)身邊的新鮮事,并在信息平臺上發(fā)布文章,經過領導審核之后,通過微信公眾號推送出去。其他員工對該文章進行轉發(fā),本公司員工以外的粉絲閱讀/轉發(fā)之后,該員工獲得相應的積分(本公司員工之間相互閱讀/轉發(fā)不積分)。同時系統(tǒng)需要具有統(tǒng)計功能,管理員能夠按照時間段、部門、轉發(fā)文章數(shù)量進行統(tǒng)計,以作為季度考核的指標。同時該公司員工規(guī)模龐大(幾千人),可能會出現(xiàn)同一時刻多人閱讀/轉發(fā)同一篇文章,并發(fā)度要求高。通過分析,發(fā)現(xiàn)微信公眾號平臺自帶的功能并不能滿足用戶需求,需要對微信公眾號平臺進行擴展。本文針對用戶需求,采用開源框架ThinkPHP和Redis緩存技術,快速搭建一套高并發(fā)的微信公眾號二次開發(fā)平臺。測試結果表明,采用ThinkPHP框架能夠減少開發(fā)難度和縮減開發(fā)周期,采用Redis緩存技術能夠實現(xiàn)1 000人左右的并發(fā)數(shù),基本上能滿足用戶需求。本文介紹的開發(fā)技術具有通用性,在快速搭建高并發(fā)的微信公眾號二次開發(fā)方面有一定的借鑒意義,能夠節(jié)約開發(fā)時間和成本。
ThinkPHP是一款基于Apache2開源協(xié)議的Web應用程序框架,自從2006年誕生以來,就受到了開發(fā)者的極大關注[2]。其作為輕量級的PHP框架,目前發(fā)展迅速,已經是三大主流框架之一(Laravel、Yii和ThinkPHP)。ThinkPHP采用MVC(Model-View- Controller)開發(fā)模式思想,將傳統(tǒng)的混雜開發(fā)模式轉變成界面顯示,邏輯控制和數(shù)據(jù)處理三層分離,每層專注于自己的開發(fā),并形成模塊化的程序塊,代碼重用度較高。各層之間耦合度較低,僅僅通過簡單的接口進行數(shù)據(jù)流通。MVC也是現(xiàn)在較為主流的開發(fā)模式,它使得Web開發(fā)更簡單快捷,能夠實現(xiàn)一處開發(fā),多處使用的效果,在各個開發(fā)語言中都能見到其身影,比較適合大中型項目應用的開發(fā)。
Redis緩存也是緩存的一種形式,它是一個開源的基于內存存儲的數(shù)據(jù)庫,可支持如鏈表、集合等多種數(shù)據(jù)類型[3]??梢允褂煤唵蔚腞edis命令快速處理大量的數(shù)據(jù),實現(xiàn)對數(shù)據(jù)高并發(fā)讀寫。傳統(tǒng)的Web數(shù)據(jù)庫數(shù)據(jù)一般存儲在硬盤中,當同時有大量用戶操作數(shù)據(jù)庫時,數(shù)據(jù)庫的連接池會承受較大的壓力,并且讀寫硬盤需要較大的IO開銷,帶來較大的訪問延遲,用戶的體驗感會大打折扣。Redis是一個內存數(shù)據(jù)庫,數(shù)據(jù)存儲在內存,所以相比傳統(tǒng)的數(shù)據(jù)庫技術,內存數(shù)據(jù)庫在讀寫速度方面更有優(yōu)勢。根據(jù)官網(wǎng)測試數(shù)據(jù)顯示:在Linux2.6下,50個并發(fā)進程執(zhí)行100 000次請求,其讀取速度在十萬次/秒左右,寫入速度在八萬轉/秒左右。由此可見,Redis讀寫效率較高。
考慮到建站的快速性和訪問的并發(fā)性,本文采用ThinkPHP和Redis技術相結合,實現(xiàn)一個高并發(fā)的微信公眾號二次開發(fā)框架,供讀者參考。本系統(tǒng)根據(jù)用戶角色劃分不同權限控制,主要分為前臺模塊和后臺兩個模塊。后端模塊主要采用開源框架Hui-admin[4]實現(xiàn)對用戶、文章、組織架構等相關數(shù)據(jù)管理,所有的操作都在PC端完成。同時實現(xiàn)對關系數(shù)據(jù)庫MySQL和內存數(shù)據(jù)Redis的管理。前端主要實現(xiàn)文章管理和用戶個人信息管理,通過與企業(yè)服務號對接,實現(xiàn)微信公眾號平臺和第三方服務器之間數(shù)據(jù)流通。前端和后端通過Redis實現(xiàn)快速交互,整個架構如圖1所示。
圖1 系統(tǒng)架構圖
2.2.1 微信公眾號與第三方系統(tǒng)對接
在微信公眾號二次開發(fā)過程中,微信官方平臺服務器其實就是一個消息轉發(fā)器,所有的用戶請求和第三方服務器的響應都經過微信服務器進行轉發(fā)[5],數(shù)據(jù)流如圖2所示。
圖2 微信公眾號二次開發(fā)數(shù)據(jù)流
(1) 用戶在微信終端向微信公眾號發(fā)送一條消息(發(fā)起請求)。
(2) 微信公眾號服務器接收到該消息之后,將此消息轉發(fā)給第三方服務器(轉發(fā)請求)。
(3) 第三方服務器解析公眾號服務器發(fā)來的請求,并將響應數(shù)據(jù)打包成消息,返回給公眾號服務器(響應請求)。
(4) 用戶收到響應數(shù)據(jù)之后,按照既定格式展現(xiàn)到頁面上(轉發(fā)響應)。
首先在通過認證的微信公眾號(服務號)頁面添加菜單項,然后將該菜單和本平臺入口文件(URL)進行綁定。在公共配置文件/Thinkphp/Application/Common/Config下的config.php文件中配置微信公眾號相關參數(shù)。其中WX_APPID是微信公眾號中第三方用戶唯一憑證,相當于第三方系統(tǒng)接入的微信平臺的登錄用戶名。
return array(
//mysql數(shù)據(jù)庫定義
′DB_TYPE′=> ′mysql′,
′DB_HOST′=> ′localhost′,
′DB_NAME′=> ′db_xxxx′,
′DB_USER′=> ′root′,
′DB_PWD′=> ′123456′,
′DB_PORT′=> 3306,
//端口號一般3306
′DB_PREFIX′=> ′tb_′,
//表前綴
…
′WX_APPID′=> ′xxxxxx′,
//微信公眾號ID
′WX_SECRET′=>′xxxxxx′,
//應用密鑰
′WEB_URL′=> ′http://xxx.com′,
//第三方系統(tǒng)
…
);
?>
2.2.2 獲取微信用戶相關信息
微信公眾號平臺使用OAuth 2.0開放協(xié)議進行身份認證,該協(xié)議允許第三方應用獲取該用戶在某一網(wǎng)站上存儲的私密資源,無需使用用戶名和密碼進行身份驗證,微信公眾號使用OAuth 2.0進行驗證一般需要三步(類似于三次握手協(xié)議):
第一步:用戶經過第三方服務器向微信公眾號服務器發(fā)送一個訪問授權請求(該請求附帶WX_APPID、重定向地址、響應消息類型等參數(shù)),該請求到達微信服務器之后,微信服務器解析該請求,將當前的URL重定向到第三方服務器,并向第三方服務器返回該用戶的CODE值。
第二步:第三方服務器收到該CODE值之后,將CODE、WX_SECRET和WX_APPID等作為參數(shù),再次向微信公眾號服務器發(fā)起請求,請求返回access token參數(shù)。
第三步:第三方服務器收到該access token參數(shù)之后,將access token和WX_APPID等作為參數(shù),最后一次向微信公眾號平臺發(fā)起請求,請求該用戶在微信平臺上存儲的私密信息(如微信號、頭像、性別等)。整個過程如圖3所示。
圖3 OAuth 2.0驗證流程圖
在OAuth 2.0驗證過程中,使用到了curl_post()方法。該方法是一個訪問HTTP協(xié)議接口,用來取得某URL對應的頁面內容。核心代碼實現(xiàn)如下:
$ch=curl_init();//初始化CURL
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//屏蔽檢測
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 120);
//設置請求超期時間
file_contents=curl_exec($ch);
//獲取URL內容
curl_close($ch);
//關閉連接
file_contents變量中存儲的就是ch變量(URL)對應頁面內容打包的JSON數(shù)據(jù),再經過json_encode方法將JSON數(shù)據(jù)轉化,即可得到用戶信息數(shù)組。
第三方服務器經過授權之后,能夠得到用戶的OpenID和相關的信息,將OpenID值寫進Redis緩存數(shù)據(jù)和MySQL數(shù)據(jù)庫的字段,表明該用戶已經和第三方系統(tǒng)進行了綁定,可以直接和第三方服務器進行數(shù)據(jù)交換。
2.2.3 Redis安裝與配置
Windows環(huán)境下,安裝Redis后,需要手動添加php的redis拓展。首先到Redis官網(wǎng)下載php_igbinary.dll和php_redis.dll兩個庫文件,然后在php.ini文件中新增 extension=php_igbinary.dll和extension= php_redis.dll兩個擴展,實現(xiàn)PHP解析器對Redis的支持。
Redis一般是通過命令來操作數(shù)據(jù),為了簡化緩存讀寫操作,ThinkPHP把所有的緩存機制封裝成了一個S方法,該方法使用簡單,跟Session使用類似。通過封裝成方法,用戶不必關注數(shù)據(jù)操作的具體細節(jié),而重在注重業(yè)務處理邏輯,大大提高開發(fā)效率。安裝好Redis之后,在/Application/ Common/Common/ function.php中配置Redis數(shù)據(jù)庫,如下所示:
function REDISCONFIG(){
//數(shù)據(jù)緩存配置
REDIS=S(array(′type′=>′redis′,′host′=> ′127.0.0.1′, ′port′=>′6379′,′prefix′=>′lz_′,));
return $ REDIS;
}
2.2.4 文章轉發(fā)操作
本系統(tǒng)需要記錄用戶文章轉發(fā)之后的閱讀量,該閱讀量需要記錄在首次轉發(fā)者的記錄中。所以需要在文章內容頁面記錄轉發(fā)數(shù)據(jù)(文章ID以及轉發(fā)者的OpenID),這里使用微信JS-SDK提供的接口。
為了能準確統(tǒng)計文章轉發(fā)數(shù)量,轉發(fā)時需要使用微信JS-SDK獲取signature簽名。需要注意的是,這里要求提前得到jsapi_ticket,它是公眾號調用微信JS接口時使用的一種網(wǎng)絡憑證[6]。正常情況下,jsapi_ticket的有效期為7 200秒,通過access_token來獲取。
if(S(′ticketStr′)){//如果ticketStr存在
$ticketStr=S(′ticketStr′);
}else{
$accessToken=$this->curl_post(″https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=″.C(′WX_APPID′).″&secret=″.C(′WX_SECRET′));
$accessTokenArr=json_decode(accessToken);
$accessTokenStr=$accessTokenArr->access_token;
$ticketJson=$this->curl_post(″https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=″.$accessTokenStr.″&type=jsapi″);
$ticketArr=json_decode($ticketJson);
$ticketStr=$ticketArr->ticket;
S(′ticketStr′,$ticketStr,7100);
}
$str=″jsapi_ticket=″.$ticketStr.″&noncestr=XXXXXXX
XXXXXXXX×tamp=1421142450&url=http://xxxx.xxxx.com″.$_SERVER[″REQUEST_URI″];
$signature=sha1($str);
$this->assign(′signature′,$signature);
接下來,在文章詳情頁面使用signature簽名,進行文章轉發(fā)操作步驟。
(1) 在文章內容頁面引入jweixin-1.2.0.js文件。
(2) 所有需要使用JS-SDK的頁面必須先進行配置,配置文件如下所示:
wx.config({
debug: true,
appId: ′{:C(′WX_APPID′′)}′,
timestamp: 1421142450,
nonceStr: ′XXXXXXXXXXXXXXXX′,
// 必填,生成簽名的隨機串
signature: ′ {$signature} ′,
// 必填,微信加密簽名
jsApiList: [
′onMenuShareTimeline′,
′onMenuShareAppMessage′,
′onMenuShareQQ′,
]
});
(3) 分享接口實現(xiàn):在這里我們使用三種分享方式:“分享到朋友圈”、“分享給朋友”和“分享到QQ”,這三種分享方式在實現(xiàn)上異曲同工,其中“分享到朋友圈”接口實現(xiàn)邏輯如表下所示。分享之后第三方服務器需要拿到被分享文章的id和被分享人的OpenID。
wx.onMenuShareTimeline({
title: ′{$info.title}′,
link: ″,
imgUrl:′{:C(′WEB_URL′)}/Public/{$info.cover}′,
success: function () {
var $arid=$.trim($′#ar_id′).val());
var $weid=$.trim($′#we_id′).val());
$.post(′{:U(′Article/forwarded′)}′,
{arId:$arid,weId:$weid},function(){});
},
cancel: function () {
}
});
2.2.5 Redis數(shù)據(jù)流的控制
(1) Redis數(shù)據(jù)流 首先在PC后臺,用戶發(fā)布文章,管理員進行審核,審核通過之后將文章ID和文章內容分別寫進articleID和articleContent_ar_id表中。articleContent_ar_id表在高并發(fā)環(huán)境下用戶方便快速讀取文章內容并呈現(xiàn),articleID表方便在文章修改時判斷文章是否已存在。
在微信前端,首先判斷用戶是否已綁定自己的微信號,如果沒有綁定,則通過注冊方式綁定。在注冊的同時將自己的工號和OpenID寫進num-openid表和staffArray表,主要用來判斷訪問者是否是本公司員工。如果已經綁定,則閱讀文章(本公司員工互相閱讀文章,文章閱讀數(shù)不變)并將文章轉發(fā)到微信好友、微信朋友圈或者QQ中。如果自己的好友(非本公司員工)閱讀文章之后,則該員工的文章閱讀數(shù)增加1,同時將訪問者的OpenID寫進文章id為ar_id的緩存表中,防止重復閱讀增加閱讀數(shù)。文章的訪問數(shù)和自己的閱讀數(shù)是數(shù)據(jù)統(tǒng)計的依據(jù),同時也是評優(yōu)評獎的重要指標,整個流程如圖4所示。
圖4 Redis數(shù)據(jù)流圖
(2) 數(shù)據(jù)備份 Redis是緩存數(shù)據(jù)庫,具有一定的生命期,為了保證數(shù)據(jù)安全,本項目采用定時備份的方式將Redis數(shù)據(jù)庫的關鍵數(shù)據(jù)及時備份到MySQL數(shù)據(jù)庫中。
軟件測試是軟件開發(fā)過程中不可缺少的環(huán)節(jié),通過測試,目的是為了發(fā)現(xiàn)系統(tǒng)與用戶需求不符或矛盾的地方,進而進行更改和完善[7]。功能測試和性能測試是一般軟件項目需要關注的兩個測試方面。功能測試是軟件測試中最基本的測試,主要驗證系統(tǒng)是否符合需求說明。性能測試主要測試系統(tǒng)在某些極端條件下是否滿足需求,其中壓力測試是一種典型的性能測試。在Web系統(tǒng)中,壓力測試主要是在系統(tǒng)同時接收大量用戶和請求時,檢測Web系統(tǒng)的響應。
本系統(tǒng)測試環(huán)境:ubuntu1204虛擬機,200 GB硬盤,8 GB內存,2 Gbit/s帶寬。Apache2.2,PHP5.3.10,MySQL5.5。
按照用戶的需求文檔,設計了30個測試用例,主要對文章審核流程和文章轉發(fā)統(tǒng)計這兩個業(yè)務邏輯復雜點進行測試。測試結果良好,測試結果和預期效果一致,測試通過率100%。
對于Web服務器來說,用戶請求響應時間是一個重要指標,它是評價系統(tǒng)性能的關鍵參數(shù)。本系統(tǒng)的性能關鍵點(并發(fā)點)主要是文章閱讀和轉發(fā)操作,使用Apache自帶的ab并發(fā)測試命令對該并發(fā)點進行測試,測試請求數(shù)為10 000,結果發(fā)現(xiàn)在并發(fā)數(shù)1 000左右的時候,系統(tǒng)平均響應時間在16.7 ms左右。也就是說1 000人同時閱讀文章或者轉發(fā)文章的時候,平均等待時間在16.7 ms左右。目前該公司人數(shù)在4 000左右,該并發(fā)數(shù)和響應時間基本上能夠滿足性能要求。
隨著“互聯(lián)網(wǎng)+”的發(fā)展,微信公眾號已經成了一種大眾化的溝通工具。為了滿足用戶的特殊需求,微信公眾號二次開發(fā)成為必要。同時隨著粉絲數(shù)量越來越龐大,一些類似抽獎、搶紅包等高并發(fā)的二次開發(fā)也迫在眉睫。本文以某企業(yè)為例,采用開源框架ThinkPHP框架和Redis緩存技術,搭建一套基于微信公眾號的高并發(fā)二次開發(fā)通用平臺,該開發(fā)技術具有通用性,在快速開發(fā)高并發(fā)的微信公眾號方面有一定的借鑒意義,能夠節(jié)約時間和經濟成本。