微信內收藏文章
假設有微信用戶A君,訂閱了公眾帳號“小道消息”(微信號DbaNotes),每天收到一篇文章推送。A君有時希望能把文章收藏起來,可以稍后閱讀或者反復欣賞。當然,可以有千百種方法來完成收藏這個事,A君是個微信腦殘粉,希望整個收藏過程僅在微信內即可完成。
印象筆記的微信公眾號“我的印象筆記”是基於微信的私有API開發的,可以把消息、文章的轉存為筆記。使用該帳號的基本的步驟是:關注“我的印象筆記”,其會提示用戶綁定印象筆記的帳戶,並發送OAuth授權登陸鏈接,點擊鏈接到印象筆記網站登陸,完成后,給“我的印象筆記”發送的內容會保存為筆記。使用微信內置Web頁面打開文章后,點擊分享按鈕,“我的印象筆記”已經內置其中,可以一鍵保存文章。總體上,“我的印象筆記”是很方便的。如果A君是印象筆記的用戶(注意,Evernote的國際帳號是無法使用的),那么A君有福了。可惜A君是Evernote用戶,而且也不太習慣在Evernote內閱讀文章。
A君是Pocket的忠實粉絲,平時在網上閑逛,遇到有意思的文章,會保存到Pocket閱讀列表,在PC上這個很簡單。A君希望能有一個類似“我的印象筆記”的公眾帳號,綁定自己的Pocket帳戶,通過發送文章鏈接的消息給該帳號,將文章添加至Pocket列表。
我們假設這個公眾帳號叫MyPocket,下面重點敘述,如何將用戶的Pocket帳戶OAuth授權給MyPocket。
節點
在整個的授權登陸過程中,涉及到的節點主要有下面四個:
節點1:微信用戶
。例如A君。
節點2:公眾號消息服務器
。用戶可見的是公眾帳號,例如MyPocket。
節點3:微信服務器
。微信官方服務器,完成1和2之間的消息傳遞。
節點4:Pocket授權登陸服務器
,Pocket應用自身的登陸服務器或頁面。
文本消息傳遞步驟
微信用戶節點1發送一條文本消息給公眾號節點2,並得到公眾帳號的回應,消息傳遞的過程如下:
(1),微信用戶節點1發送消息
(2),消息到達節點3,對消息進行封裝通過HTTP POST推送給節點2
(3),消息到達節點2,處理后對HTTP進行響應,返回給節點3,轉發給節點1
(4),消息到達節點1,微信用戶接收到消息回應
注意,目前節點2是無法主動發送消息給用戶的,僅能在收到節點3的消息推送后,進行消息回復。
OAuth授權登陸步驟
和普通的在瀏覽器中完成的OAuth授權登陸有所不同,在微信中OAuth登陸的基本步驟是:
1,微信用戶節點1發送特定表識消息(例如“auth”)開始OAuth授權登陸
2,節點2收到消息后:
(1)記住節點1的標識串FromUserName,需要保存
(2)到節點4獲取request token,需要保存
(3)給節點1消息回復:用戶授權登陸的地址鏈接,地址鏈接中需要包含:用戶表識串FromUserName和授權完成后的回調(callback)地址
3,節點1打開登陸鏈接,微信內置瀏覽器中填寫帳戶,進行授權
4,節點4重定向至節點2的callback地址
5,節點2處理授權登陸callback,根據request token獲取access token,授權完成,需要保存access token。
下面是對該過程的幾點說明:
(1)消息推送中所攜帶的用戶相關信息只有FromUserName,是一個加密后的字符串,形如oGfS0jrOSOwJXqNTIy9B8WI8sEac。因此直接獲取用戶的微信號或者昵稱存在困難。據從網上查詢到的信息看,一個微信用戶發送給某特定的公眾帳號的所有消息,該FromUserName是固定的。可用來唯一標識節點1。
(2)步驟2中的FromUserName、request token和步驟5的access token都需要保存。因為節點2會和節點3,以及節點1的瀏覽器發生HTTP交互,無法使用瀏覽器cookie,此處使用數據庫進行保存操作。
(3)瀏覽器支持。因為OAuth登陸,其中一個步驟要到第三方的登陸授權界面進行登陸,需要用到瀏覽器,微信內置的瀏覽器,可以完美完成此任務。
代碼
本例采用python的flask框架實現了一個小例子,主要的代碼整理如下。授權登陸的步驟2代碼:
@app.route('/weixin', methods=['POST']) def weixin_msg(): data = request.data msg = parse_msg(data) content = msg['Content'] username = msg['FromUserName'] if content == 'auth': pocket = Pocket(POCKET_CONSUMER_KEY, BASE_URL + url_for('auth_callback') + '?username=' + username) code = pocket.get_request_token() #code即為request token url = pocket.get_authorize_url(code) #保存code和username user = User(username) user.pocket_code = code db.session.add(user) db.session.commit() rmsg = u'點擊下面鏈接登陸Pocket並授權給給我\n\n' + rmsg.encode('utf-8') return response_text_msg(msg, rmsg) return help_msg()
步驟2返回的認證地址Authorize Url,是通過微信消息回復給節點1的,由節點1手動點擊鏈接打開,此處無法使用cookie,本例采用數據庫保存session數據。其中BASE_URL + url_for('auth_callback') + '?username=' + username為重定向地址,節點4確認授權以后,重定向至節點2的,新增了"username"參數,可以理解為session id。
步驟5代碼:
@app.route('/auth_callback') def auth_callback(): username = request.args.get('username') user = User.query.filter_by(username=username).first() pocket = Pocket(POCKET_CONSUMER_KEY) resp = pocket.get_access_token(user.pocket_code) user.pocket_token = resp['access_token'] user.pocket_username = resp['username'] db.session.commit() return '<html><head></head><body><h1>認證成功,發送文章鏈接給MyPocket,即可保存到Pocket閱讀列表。</h1></body></html>'
授權完成后,用戶直接發送文章鏈接,節點2匹配到Url地址,即添加到Pocket列表:
def add_item_to_pocket(username, content): r = r"(http://[^ ]+)" urls = re.findall(r, content) rmsg = u'' user = User.query.filter_by(username=username).first() pocket = Pocket(POCKET_CONSUMER_KEY) pocket.set_access_token(user.pocket_token) for url in urls: itemjson = pocket.add(url=url) item = json.dumps(itemjson) rmsg += u'已添加"%s"至Pocket\n' % item['title'] return rmsg
用法
A君想要收藏小道君發送的文章“「大概8點20分發」”,在微信中點擊推送消息,內置瀏覽器打開文章,點擊右上角的分享按鈕,點選“復制鏈接”,打開MyPocket,粘貼,發送的鏈接如下:
http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5ODIyMTE0MA==&appmsgid=10000250&itemidx=1#wechat_redirect
這樣,A君就可以在3月17日的早晨大概8點20分在Pocket中欣賞這篇好文了。你不妨也試試看:
資源
1,Pocket API的python sdk。