相信讀者同學們都了解wechat-admin,甚至在本地運行過了。今天是wechat-admin項目系列文章的第一篇:項目設計。
在你技術學習的過程中或者已經具備了開發所需要的知識時,某一天靈光一閃決定去做一個(web)項目。那麼通常前期分這麼幾步:
需求確認。切忌一上來就寫代碼,先得在心中能把一個項目能清晰的拆分成一條條的需求,另外也要不斷地和需求方確認你的理解是不是正確。
技術確認。首先是確定你能不能hold得住,別攤子鋪的太大最後摟不住,或者在預定時間內無法完成。
用較短時間對技術實現難點確認。熟悉的東西寫出來只是時間問題,那些未知不可控的才是你需要首先確認的,如果發現一開始的技術選型有問題,那麼就要儘早的停止改其他方案。
我希望大家在向下看之前,(閉上眼)思考一下:
假如現在讓你來寫這個項目,你用什麼技術方案,你準備如何的實現?
好的,思考之後。來看看我是怎麼做的,為什麼這樣做,以及這個過程中有什麼調整和故事吧。
需求 & 選型大家可以看到我在「特性」中的功能列表,其實一開始的需求只有:
微信掃碼登錄
拉取和存儲聯繫人、群列表、群成員等信息
自動建群,加人
Web管理頁面展示這些信息
Web頁面上可設置一些需要的功能參數
消息提醒
自動回復機器人
那麼接著拆分這些需求。由於我主要是在周末和晚上這種閒暇零散時間,所以我希望讓這個拆分粒度儘量的小,控制在一個點1-2小時,最多半天這個標準上。有些需求可以同時做(防止長時間做一件事無聊),有些是其他的需求完成才可以開始的。所以,需求和選型是這樣:
微信掃碼登錄這個是一開始要做的,我對ItChat/wxpy並不熟悉,這個是整個項目唯一的感覺「不安全」的點了:微信登錄和其他常規登錄的體驗是完全不一樣的。別的都是帳戶/密碼、手機號、第三方登錄,案例很多,很好做。但是微信是要用手機掃碼,所以我要解決2個問題:
加「鉤子」,把登錄微信的狀態(等待掃碼/掃碼完成等待確認/確認完成)及時的通知我,讓我在Web頁面上進行對應的步驟
需要通過某種方式和服務端實現保持一個長的連接,收到這個通知可以推送數據到瀏覽器
進一步去確認需求啦。首先閱讀ItChat/wxpy源碼,發現它能拿到這種通知,但是設計的是在終端用log的方式列印出來,不過本身支持callback函數也能實現鉤子函數。不過我還是fork了他倆。解釋下原因:
我不喜歡callback的方式,這會提高項目的複雜程度,高聚合。所以我要使用信號解耦這部分內容。想必看過我的書的同學對信號都深有感觸了吧。
給ItChat提交過代碼,好幾天沒人理,索性自己維護fork版本,遇到不滿足需要就可以快速改,提高效率
另外後來還踩了一個坑兒,就是頁面動態改掃碼圖片的src會有緩存。所以在信號中把掃碼圖片變成Data URL協議的方式傳遞迴來。
向瀏覽器推送數據更知名的方案是Websockets,它可以雙向的數據推送,不過太重了用不到,我需要一個輕量級的方案。由於豆瓣有一些場景也是SSE(Server Sent Events),為了學習它,我也選擇了SSE。
拉取和存儲聯繫人、群列表、群成員等信息wxpy提供了直接的API拉取這些信息,但是為什麼要本地存呢?
最主要的,為了降低調用微信接口的次數,降低被封的風險。當我用正確的方式存下來,再加上我改良的wxpy的puid方案,同樣可以實現對這些信息進程展示、篩選等查詢內容
開源嘛,就是為了多給大家一個學習的源碼項目的機會,想展示SQLAlchemy的更多用法
另外掃碼登錄之後,拉取和存儲的過程可能會比較長,另外在Web頁面上還有「強制刷新」的功能,這些如果讓頁面等待用戶體驗很差,都需要異步執行,所以用Celery異步的執行。
有個插曲,其實一開始覺得這種小項目用Celery小題大做了,選擇了rq,但是隨著我的需求變多變複雜(之後的文章會提到),rq的局限性就越來越凸顯了。以前我對rq、huey這種框架都是「小項目不妨用用」的態度,不過現在我真的用過了之後才發現在Python圈 Celery永遠是首選,請相信我。
自動建群,拉人操作都是由wxpy封裝的(wxpy封裝了ItChat),它不支持通常說明Web微信沒有這個功能。需要注意的是,建群時還需要至少2個人,要不然不能建群,建群接口當天也會被封。所以「自動建群」需要點技術選型,那就是在設置頁面有一個項,包含默認拉的人都有誰,那麼需要存起來,我在這個項目把這樣的內容都存在了Redis裡面。
由於公司基本設施的問題,我Redis用的很少,常見也很簡單,一直沒有用過Redis的ORM,這次項目其實是為了嘗試一下。不過一開始使用的是我fork的redisco,我給它增加了Python 3的支持。不過後來幹掉換成了現在用的Walrus,因為在使用過程發現太難用了。
這種早期的新技術選型失敗是不可避免的,不過還是在我可控制的範圍。
Web管理頁面展示這些信息,並且可設置功能參數,消息提醒這也是本文的重點之一了。Python Web開發者通常都不是單純的後端開發,所以前端的知識、框架、工具也是要熟練使用。網上這種前後端結合的項目和經驗比較少,本文也來談一談:
為什麼選擇了Vue?如果你不是一個專職前端工程師,並且也沒有打算未來轉成前端開發者,但是由於工作或者興趣需要寫HTML、JS時,使用框架是一個正確的選擇。過去純手寫JS或者用jQuery的方式寫代碼效率是很低下,尤其在頁面交互複雜時,而現在有React、Vue這些框架,幫助你省太多的事情了。去年的網易雲音樂精彩評論(https://github.com/awesome-archive/commentbox)使用的是 React + Mobx + Fetch + Material-UI + ES6 + Webpack + Babel,對應的技術選型文章可以看commentbox用到了那些前端技術(https://zhuanlan.zhihu.com/p/22806115)。
最近工作中都在使用Vue,比如豆瓣電影「選影視」以及新的電影管理後臺(Vue+Vue-Material),我在這裡向各位Python開發者極力推薦Vue,理由如下:
最大程度的降低了初學者的學習曲線。
數據雙向綁定。實現一個相對複雜的頁面需要的代碼量很少。更多MVVM和前端發展歷史可以看我之前寫的 淺談MVC、MTV和MVVM
單文件組件化和它的語法對於寫模板的同學來說最易接受
文檔和周邊生態都相對完善
Vue-cli這個命令行腳手架包含了豐富的模板,可以非常快的初始化出來一個項目,極為方便
為什麼選擇Element-UI我嘗試過Vue下的各種UI庫,Element是其中功能最全,API和文檔最完善和最易於使用的。舉個例子,我用Vue-Material時經常需要翻源碼了解用法,貨比貨得扔啊。但是它也是我的選型(也是為了配合廠內其它的Material-UI),含著淚也要用下去...
另外,如果你想開啟一個使用Material Design的新項目,建議使用Muse-UI
如何實現前後端的交互?不止一個同學問過我這個問題。三點來概括吧:
前端是一個單頁面應用,路由由vue-router來實現,對於後端來說,只需要渲染一個index.html就好了。
後端由Python的Web框架提供API,對Flask進行一些定製,讓它返回的內容mimetype就是application/json,並且統一封裝了返回的格式
前端在打開頁面或者在事件中通過Axios這個HTTP客戶端庫發出請求到後端,後端接口接收並返回對應的內容
自動回復機器人在我念書的年代,也上過人人網,當時小黃雞非常知名,覺得很神奇。當我工作,尤其是做了開發之後,發現其實對於API調用者來說是沒有技術含量的。現在市面上有很多知名的機器人,使用它們的每日限額的免費接口就可以。另外我也用到了一些機器學習的ChatterBot。
我改了wxpy的源碼,用插件的方式讓這些額外的功能可插拔。
其他需求剩下的那些功能,都是在現有的技術選型基礎上去實現的。有些是過程中產生的靈感,有的是閱讀源碼的時候發現的。