微信開發小結——積累與沉澱

前言

微信開發是個人、企業或組織在擁有超大用戶羣體的微信應用上,利用微信公衆平臺,開發類似插件或服務的輕應用。微信公衆平臺分爲三種:訂閱號:主要面向媒體和個人,旨在爲用戶提供信息資訊,每天能夠羣發1條消息,通過微信認證,可獲得菜單、獲得用戶信息等接口權限;服務號:主要面向企業、政府和組織,旨在爲用戶提供服務,每月能夠羣發4條消息,通過微信認證,可獲得高級接口權限;企業號:主要面向企業,旨在爲企業用戶提供移動端辦公,只有企業通訊錄中的用戶才能關注使用,可以自由推送消息,不受限制,保密消息,防轉發。期間我負責開發了基於服務號的微信投票和基於企業號的微信ERP,以下我主要從開發的角度介紹期間遇到的問題和心得體會。

前提準備

1、微信公衆號申請,並通過微信認證。

2、準備一個二級以上域名,域名必須要備案。

3、對於需要自定義開發,需要提供可以部署程序的公網服務器。

對於2、3點,可以由開發公司提供,只需提供客戶方一個管理後臺地址和管理員賬號密碼,由客戶方管理人員進行維護。

開發者認證獲取票據

無論何種公衆平臺,開發者第一步工作是,獲取AccessToken票據,因爲絕大部分調用接口時都需攜帶AccessToken票據。AccessToken需要用申請的公衆平臺提供的CorpID和Secret(服務號則用AppID和Secret)來換取,不同的Secret會返回不同的AccessToken,換取的過程就是一次接口的調用。每次獲取的AccessToken有效期是2個小時,失效後需要重新換取,我利用緩存處理把每次獲取的AccessToken保存起來,設置7100秒,防止臨界值的情況,並把它設置成靜態屬性,封裝獲取過程。在每次調用微信接口時,直接校驗是否失效。

static string AccessToken { get { return qyUtils.GetTenket(); } }
        /// <summary>
        /// 應用toket獲取
        /// </summary>
        /// <returns></returns>
        public static string GetTenket()
        {
            try
            {
                var cache = new mCache("token", "qyAccessToken");
                if (cache.ValidCache()) return cache.GetCache().ToString();
                string url = string.Format("{0}/cgi-bin/gettoken", Globals.QY_HTTP);
                StringBuilder param = new StringBuilder();
                param.Append("corpid=");
                param.Append(Globals.CORP_ID);
                param.Append("&corpsecret=");
                param.Append(Globals.CORP_SECRET);
                string strValue = Utils.GetData(url, param.ToString());
                ACCESS_TOKEN ac_token = JsonConvert.DeserializeObject<ACCESS_TOKEN>(strValue);
                if (ac_token.errcode == ReturnCode.請求成功)
                {
                    cache.ExpireTime = 7100;
                    cache.SetCache(ac_token.access_token);
                    return ac_token.access_token;
                }
                else
                {
                    HttpContext.Current.Response.Write("<script>$.alert('" + ac_token.errmsg + "');</script>");
                    return null;
                }
            }
            catch { }
            return null;
        }

接口封裝

工慾善其事必先利其器!微信提供的API接口都是HTTP的POST請求和Get請求,我們可以封裝成工具類,方面後期的使用。對於Get請求,我把URL變量作爲參數傳入發送HttpWebRequest請求,獲取HttpWebResponse響應,反序列化結果判斷請求是否成功,對於Post請求也差不多,只是多加一個傳入數據的參數變量。

public static string PostData(string url, string data)
        {
            data = Regex.Unescape(data);
            string json = HttpPost(url, data);
            try
            {
                var item = JsonConvert.DeserializeObject<WxJsonResult>(json);
                if (item.errcode != 0)
                {
                    if (item.errcode == ReturnCode.獲取access_token時AppSecret錯誤或者access_token無效 || item.errcode == ReturnCode.oauth_code超時)
                    {
                        ClearTenket();
                    }
                    item.errmsg = item.errcode.ToString();
                    json = JsonConvert.SerializeObject(item);
                }
            }
            catch { }
            return json;
        }
公衆號經常有需要用到一些臨時性的多媒體素材的場景,是通過media_id來進行的,而對於上傳文件的POST請求,我直接使用的.NET語言自帶的WebClient進行處理,先將文件上傳到自己服務器端,使用相對路徑獲取服務器上的文件資源,調用微信公衆號API,上傳文件,返回媒體文件唯一標識。
public static QyUploadTemp WeChatUpload(string url, string type)
        {
            try
            {
                if (!string.IsNullOrEmpty(qyUtils.GetTenket()))
                {
                    string posturl = string.Format("{0}/cgi-bin/media/upload?access_token={1}&type={2}", Globals.QY_HTTP, AccessToken, type);
                    System.Net.WebClient webclient = new System.Net.WebClient();
                    string media = HttpContext.Current.Server.MapPath(url);
                    byte[] be = webclient.UploadFile(new Uri(String.Format(posturl, AccessToken, type)), media);
                    string content = Encoding.Default.GetString(be);
                    var result = JsonConvert.DeserializeObject<QyUploadTemp>(content);
                    if (result.errcode == ReturnCode_QY.請求成功)
                    {
                        return result;
                    }
                }
            }
            catch { }
            return null;
        }

身份驗證

微信應用經常需要獲取用戶身份信息,這就需要通過OAuth2.0驗證接口。利用.NET應用的FormsAuthentication機制,判斷請求是否已經過身份驗證,否則跳轉統一的授權認證處理/OAuth/QyLogOn調用OAuth驗證接口獲取code,這裏需要指定成功獲取code之後,根據code獲取成員信息,並記錄用戶信息,身份驗證處理。將需獲取用戶身份信息的方法繼承基類QyBaseController,就可以在每次獲取用戶身份前,先OAuth驗證,如果已經過身份驗證,則無需重複身份驗證。

1、未通過身份驗證處理
		public ActionResult QyLogOn(string returnUrl)
        {
            if (!String.IsNullOrEmpty(returnUrl))
            {
                Session["WX_returnUrl"] = returnUrl;
            }
            string action = "OAuth/QyLogOnOAuth";
            return Redirect(Utils.GetAuthorizeUrl(Globals.CORP_ID, action, "", OAuthScope.snsapi_base));
        }
2、調用OAuth驗證接口獲取code,這裏主要特別注意的是redirectUrl必須保證和瀏覽器中的地址一致
		public static string GetAuthorizeUrl(string appId, string action, string state, OAuthScope scope, string responseType = "code")
        {
            string redirectUrl = HttpUtility.UrlEncode(string.Format("{0}/{1}", Globals.DOMAIN_URL, action));
            string url =
            string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect",
                            appId, redirectUrl, responseType, scope, state);
            return url;
        }
3、根據code獲取成員信息,並記錄用戶信息,身份驗證處理
		public ActionResult QyLogOnOAuth(string code, string state)
        {
            if (string.IsNullOrEmpty(code)) return Content("您拒絕了授權!");
            try
            {
                //通過,用code獲取成員信息
                OAuthUserInfoResult result = qyUtils.GetUserInfobyCode(code);
                if (string.IsNullOrEmpty(result.UserId))
                    return Content("<div><span class='fa fa-error'>您不是企業用戶,請通知管理員添加!</span></div>");
                var user = qyUtils.GetUserInfobyUserId(result.UserId);
                qyWxUser.LogOn(user);
                if (Session["WX_returnUrl"] != null) { return Redirect(Session["WX_returnUrl"].ToString()); }
            }
            catch (Exception ex)
            {
                return Content(ex.Message);
            }
            return RedirectToAction("ErrorTip", "Account");
        }

微信端UI框架

由於之前缺乏移動端開發經驗,對於前端框架都不熟悉,只能網上了解一些開源的UI框架,又因爲自己畢竟不是專業的前端開發工程師,最佳的選擇是自帶功能豐富組件的開源UI庫。經過篩選,最先嚐試的是由微信官方的推的weui,發現只有一些簡單的組件,對於js請求處理響應都得自己寫,便放棄了。後來瞭解到由阿里巴巴基於Framework7開發的SUI庫,輕量、精美,實現了下拉刷新、日曆、省市區選擇器等功能非常強大的組件。這種資源對於一個只是剛剛入門的前端開發來說,無疑是最好的。但卻忽略了很重要的一點,對於這種開源項目來說,團隊的的持續維護更新,是至關重要的。隨着使用頻率增加,以及業務要求的複雜,SUI框架中隱藏的問題漸漸暴露出來:路由跳轉頁面和路由返回上一個頁面存在問題,下拉滾動加載數據不能與上拉刷新並存,Android 端微信顯示效果比IOS端微信差,日曆組件初次打開不會聚焦輸入框裏的時間;這套UI庫是引用Zepto.js,再引用Jquery庫,會出現衝突以致組件失效、不穩定,而且SUI的主力開發人員已離開阿里巴巴,沒有人繼續負責維護這個項目了。後來瞭解到SUI框架的作者另外開了一個新的項目Light7,相當於SUI的升級版,修復了很多bug,還擴展了一些新的功能,而且會長期維護更新,於是又切換新的UI庫。

這次前端UI框架的選擇,給我最大的體會是項目風險管理,在開發過程中引入新技術,不可避免地要遇到各種風險。對於新技術開發,在項目開發早期,就應該建立系統的架構,解決關鍵技術難題、開發的基礎構件,對所需要應用的技術做深度探索。越是技術複雜度高的項目,就越應該早地處理技術難題。新技術開發是探索性很強的工作,潛在着許多失敗的風險,在可行性分析階段,要廣泛蒐集相關信息,設計多種可行方案,進行充分論證。如果針對新技術,沒有經驗可借鑑,探索過程中要充分利用互聯網資源,學習同行經驗,往往事半功倍。

用戶體驗

微信端開發類似一個App軟件應用,頁面數據渲染速度對用戶體驗是至關重要的,微信端數據加載採用的是Juicer模板渲染的方式,高效、輕量的前端 (Javascript) 模板引擎,當用戶進行滾動加載或者下拉刷新時,體驗很流暢。對於ASP.NET MVC程序,需要解決一個符號的衝突,把@符號換成&,然後把後端處理得到的數據封裝成指定的JSON格式,綁定模板即可。模板的定義(注:這裏的"{&"符號使用必須修改juicer.js中的"{@"):

<script type="text/template" id="morder_li_head">
    {&if head != null }
    <div class="list-group">
        <ul class="list-block list-container media-list" >
            <li class="list-group-title" >${head.ItemClassName}</li>
        </ul>
    </div>
    {&/if}
</script>
封裝JS調用,以參數的形式指定渲染的模板ID和數據,統一處理渲染數據的判斷過程,降低代碼冗餘:
initTpl = function (e, t, n) {
	n || (n = !1),
	"feed_list" != e || t.showDing || 0 == t.showDing || (t.showDing = !0);
	var i = $("#" + e).html(),
	a = juicer(i),
	o = a.render(t);
	console.log(t);
	return t.page && !n && t.total > t.page * t.count && null != t.data && t.data.length > 0 && !n && (o += loadMoreHtml),
	o
}
調用方法就是:
list = JSON.parse(e);
$("#popup-info").find("#inventoryview").html(initTpl("morder_li_head ",  list));

管理後臺

當申請微信公衆號,都會有一個相應的微信管理登陸後臺,但是,對於微信端很多自定義功能,需要管理後臺進行統一的管理,比如:微信投票項目的發起,參與公司的審覈,投票數據統計,ERP用戶與微信賬號的對應關係,ERP菜單權限分配。數據處理採用的優秀的開源項目jQuery MiniUI,豐富的UI控件、高度的穩定性、強大的擴展能力和平滑的版本升級能力。

集成的功能:系統管理裏添加了登陸用戶角色和權限管理,指定不同用戶類型不同的功能,最高管理員權限用戶可以管理多個微信公衆號(這一點仍在開發中...),只需開放企業管理員賬戶給相應客戶即可。管理後臺添加了日誌管理功能,做到錯誤記錄,方便管理員跟蹤。對於微信ERP主要是企業號應用管理,微信端ERP菜單管理,微信用戶添加、修改和關聯ERP用戶,分配ERP菜單權限,以及指定微信用戶發送文本、圖文、圖片、文件、視頻、語音消息。


注:後續我還會針對應用的技術進行拆分講解記錄,主要是給自己做一個積累,也供大家學習參考,少走彎路。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章