平臺技術(shù)-消息服務(wù)使用介紹
消息服務(wù)是開放平臺為提高應(yīng)用API調(diào)用效率而推出的一種主動推送服務(wù)( From淘寶 ),推送內(nèi)容包括(淘寶交易、商品、退款等信息),基于該推送服務(wù),應(yīng)用獲取淘寶數(shù)據(jù)不需再不停輪詢API,僅需在接收到淘寶推送的消息時調(diào)用API獲取即可,大大提高API調(diào)用效率和降低API使用費用。同時還提供消息回流服務(wù)( To淘寶 ),應(yīng)用可將信息回流到淘寶,做商品數(shù)源服務(wù)等。
From淘寶:即淘寶向外推送淘寶(包括天貓)的交易、商品、退款等官方消息。
To淘寶:即向淘寶回流消息。
那么如何使用消息服務(wù)呢? 請看以下是消息服務(wù) From淘寶 和 To淘寶 兩種方式的詳細(xì)使用說明。
From淘寶消息服務(wù)使用
應(yīng)用訂閱消息
進(jìn)入ISV控制臺,在“應(yīng)用管理->消息服務(wù)->訂閱消息”頁面,選擇需要的消息進(jìn)行訂閱,點擊相應(yīng)消息后面的“訂閱”即可
訂閱消息成功,可以在“我的訂閱”中查看已經(jīng)成功訂閱的消息。如果需要取消消息的訂閱,直接點擊 “取消訂閱”。點擊消息名稱可以查看每個消息返回的詳細(xì)字段信息。
給用戶開通消息
調(diào)用taobao.tmc.user.permit接口給用戶(即淘寶或天貓商家)開通,可以選擇只給用戶開通部分消息類型,也可全部開通。具體可看該API 入?yún)⒄f明。
備注:
- 給用戶開通消息前提是用戶已經(jīng)給應(yīng)用授權(quán),如未授權(quán),請參考獲取用戶授權(quán)說明。
- 取消用戶的消息服務(wù)調(diào)用taobao.tmc.user.cancel接口。
- 可以通過接口taobao.tmc.user.get獲取用戶已開通消息,入?yún)⒈仨気斎雐s_valid,topics,modified來判斷用戶授權(quán)消息是否成功
- 消息服務(wù)API文檔:點擊這里查看
代碼實現(xiàn)接收消息
正式環(huán)境服務(wù)地址:ws://mc.api.taobao.com/
沙箱環(huán)境服務(wù)地址:ws://mc.api.tbsandbox.com/
接收消息,實現(xiàn)方式有兩種: 通過SDK接收消息 、 通過API接收消息 ,推薦采用SDK接收消息。
通過SDK接收消息
目前支持JAVA與.NET語言,其它語言建議采用API接收消息。通過SDK接收消息只需要關(guān)注業(yè)務(wù)的處理,不需要操心消息重發(fā)、確認(rèn)、長連接的重連等操作,SDK會自動處理好一切。
JAVA接口使用說明
public interface MessageHandler { /** * 消息通道客戶端收到消息后,會回調(diào)該方法處理具體的業(yè)務(wù),處理結(jié)果可以通過以下兩種方式來表述: * <ul> * <li>拋出異?;蛟O(shè)置status.fail()表明消息處理失敗,需要消息通道服務(wù)端重發(fā) * <li>不拋出異常,也沒有設(shè)置status信息,則表明消息處理成功,消息通道服務(wù)端不會再投遞此消息 * * @param message 消息內(nèi)容 * @param status 處理結(jié)果,如果調(diào)用status.fail(),消息通道將會擇機(jī)重發(fā)消息;否則,消息通道認(rèn)為消息處理成功 * @throws Exception 消息處理失敗,消息通道將會擇機(jī)重發(fā)消息 */ public void onMessage(Message message, MessageStatus status) throws Exception; }
JAVA使用代碼示例
TmcClient client = new TmcClient("app_key", "app_secret", "default"); // 關(guān)于default參考消息分組說明 client.setMessageHandler(new MessageHandler() { public void onMessage(Message message, MessageStatus status) { try { System.out.println(message.getContent()); System.out.println(message.getTopic()); } catch (Exception e) { e.printStackTrace(); status.fail(); // 消息處理失敗回滾,服務(wù)端需要重發(fā) // 重試注意:不是所有的異常都需要系統(tǒng)重試。 // 對于字段不全、主鍵沖突問題,導(dǎo)致寫DB異常,不可重試,否則消息會一直重發(fā) // 對于,由于網(wǎng)絡(luò)問題,權(quán)限問題導(dǎo)致的失敗,可重試。 // 重試時間 5分鐘不等,不要濫用,否則會引起雪崩 } } }); client.connect("ws://mc.api.taobao.com"); // 消息環(huán)境地址:ws://mc.api.tbsandbox.com/注: 采用Java main方法在Eclipse里面運行上面的代碼測試時,請在client.connect()后面加上Thread.sleep讓main線程等待一段 時間結(jié)束,以便觀察消息的實時接收情況,否則main線程結(jié)束后,TMC長連接也會跟著斷開。如果是在web服務(wù)器上運行上面的代碼,則不用在 client.connect()后面加任何Thread.sleep代碼,也不需要在外面包一層while(true)循環(huán),因為web服務(wù)器上的主線 程只要服務(wù)器不關(guān)閉都是不會結(jié)束的,TMC的長連接會一直保持。
C#使用示例代碼
TmcClient client = new TmcClient("appkey", "appsecret", "default"); // 關(guān)于default參考消息分組說明 client.OnMessage += (s, e) => { try { Console.WriteLine(e.Message.Topic); Console.WriteLine(e.Message.Content); // 默認(rèn)不拋出異常則認(rèn)為消息處理成功 } catch (Exception exp) { Console.WriteLine(exp.StackTrace); e.Fail(); // 消息處理失敗回滾,服務(wù)端需要重發(fā) // 重試注意:不是所有的異常都需要系統(tǒng)重試。 //對于字段不全、主鍵沖突問題,導(dǎo)致寫DB異常,不可重試,否則消息會一直重發(fā) // 對于,由于網(wǎng)絡(luò)問題,權(quán)限問題導(dǎo)致的失敗,可重試。 // 重試時間 5分鐘不等,不要濫用,否則會引起雪崩 } }; client.Connect("ws://mc.api.taobao.com/"); // 消息環(huán)境地址:ws://mc.api.tbsandbox.com/注: 采用C# Main方法在VS控制臺工程里面運行上面的代碼測試時,請在client.Connect后面加上Console.Read()或 Thread.Sleep讓main線程暫時不結(jié)束,以便觀察消息的實時接收情況,否則Main線程結(jié)束后,TMC長連接也會跟著斷開。如果是在IIS服 務(wù)器或C#應(yīng)用程序里面運行上面的代碼,則不用在client.Connect后面加任何等待的代碼,也不需要在外面包一層while(true)循環(huán),只要保持IIS服務(wù)器或C#應(yīng)用程序不關(guān)閉,TMC的長連接會一直保持。
通過API接收消息
提供API接收消息的目的是那種對多線程和長連接處理不方便的語言使用的,比如PHP、Python,這些語言官方暫時沒有提供SDK,可以通過下面兩個API配合使用也能達(dá)到接收和確認(rèn)消息的目的。 推薦盡量用SDK方式,如果必須使用API,建議調(diào)用taobao.tmc.messages.consume接口時盡量不要并發(fā)或并發(fā)量不要太大,API使用存在實時性不是很高的情況,如果實時性要求高建議還是用SDK。
基本步驟:
- 首先消費消息:API名稱:taobao.tmc.messages.consume消息消費后,指針自動后移,下次調(diào)用自動獲取到未消費過的消息,但是消費確認(rèn)后的消息無法再次獲取。
- 然后確認(rèn)消息:API名稱:taobao.tmc.messages.confirm獲取消息后,如果不確認(rèn),消息服務(wù)會選擇時機(jī)重發(fā),重發(fā)次數(shù)由消息服務(wù)控制,如果消息3天內(nèi)都沒有被確認(rèn)將會被刪除。
JAVA示例代碼
TaobaoClient client = new DefaultTaobaoClient("http://gw.api.taobao.com/router/rest", "app_key", "app_secret", "json"); do { long quantity = 100L; TmcMessagesConsumeResponse rsp = null; do { TmcMessagesConsumeRequest req = new TmcMessagesConsumeRequest(); req.setQuantity(quantity); req.setGroupName("default"); rsp = client.execute(req); if (rsp.isSuccess() && rsp.getMessages() != null) { for (TmcMessage msg : rsp.getMessages()) { // handle message System.out.println(msg.getContent()); System.out.println(msg.getTopic()); // confirm message TmcMessagesConfirmRequest cReq = new TmcMessagesConfirmRequest(); cReq.setGroupName("default"); cReq.setsMessageIds(String.valueOf(msg.getId())); TmcMessagesConfirmResponse cRsp = client.execute(cReq); System.out.println(cRsp.getBody()); } } System.out.println(rsp.getBody()); } while (rsp != null && rsp.isSuccess() && rsp.getMessages() != null && rsp.getMessages().size() == quantity); Thread.sleep(1000L); } while (true);
C#示例代碼
ITopClient client = new DefaultTopClient("http://gw.api.taobao.com/router/rest", "app_key", "app_secret", "json"); do { long quantity = 100L; TmcMessagesConsumeResponse rsp = null; do { TmcMessagesConsumeRequest req = new TmcMessagesConsumeRequest(); req.GroupName = "default"; req.Quantity = quantity; rsp = client.Execute(req); if (!rsp.IsError && rsp.Messages != null) { foreach (TmcMessage msg in Messages) { // handle message Console.WriteLine(msg.Topic); Console.WriteLine(msg.Content); // confirm message TmcMessagesConfirmRequest cReq = new TmcMessagesConfirmRequest(); cReq.GroupName = "default"; cReq.SMessageIds = msg.Id.ToString(); TmcMessagesConfirmResponse cRsp = client.Execute(cReq); Console.WriteLine(cRsp.Body); } } Console.WriteLine(rsp.Body); } while (rsp != null && !rsp.IsError && rsp.Messages != null && rsp.Messages.Count == quantity); Thread.Sleep(new TimeSpan(0, 0, 1)); } while (true);注:通過API拉取消息的平均RT在網(wǎng)絡(luò)好的情況下能達(dá)到10毫秒左右,每次消費得到的消息為空時,務(wù)必暫停至少1秒才去執(zhí)行下一次循環(huán)拉取消息,否則會產(chǎn)生很多無謂的請求,白白浪費服務(wù)端的資源,以及應(yīng)用自身的API流量包。
消息分組使用介紹
用戶數(shù)量很大需要多臺機(jī)器組成一個集群來接收消息,或者對商家進(jìn)行隔離獨立接收消息的時候。不管是SDK還是API都可以通過多連接接收消息。
消息服務(wù)支持多連接有兩種方式:Ⅰ、創(chuàng)建多個用戶分組,每個用戶分組建立一個連接。Ⅱ、同一個分組建立多個連接
- 創(chuàng)建分組:調(diào)用接口taobao.tmc.group.add創(chuàng)建自定義分組。注:消息服務(wù)會為應(yīng)用創(chuàng)建一個default分組,沒有分配到指定分組【group】的用戶都屬于default分組,通過SDK或API消費消息時,如果不指定分組,就表示采用默認(rèn)分組連接。
- 刪除分組:調(diào)用接口taobao.tmc.group.delete刪除指定的分組或分組下的用戶。注:每個應(yīng)用最多創(chuàng)建50個分組,每個分組用戶數(shù)不限。
To淘寶消息服務(wù)使用
訂閱數(shù)據(jù)回傳消息
在應(yīng)用管理后臺,點擊“訂閱消息”,如果該消息沒有權(quán)限,則通過點擊“申請權(quán)限”,進(jìn)入申請相應(yīng)的增值包
代碼實現(xiàn)推送消息
對于消息的回傳,有兩種方式: 通過API發(fā)布消息 、 通過SDK發(fā)布消息 ,推薦采用API發(fā)布消息。
通過API發(fā)布消息
具體使用說明,請參考API文檔:taobao.tmc.message.produce
通過SDK發(fā)布消息(不推薦)
目前支持JAVA與.NET語言,其它語言建議采用API發(fā)布消息。
JAVA代碼示例
TmcClient client = new TmcClient("app_key", "app_secret", "default"); client.connect("ws://mc.api.taobao.com/"); for (int i = 0; i < 10; i++) { client.send("helloworld-topic", "{helloworld-content}", "session_key"); }
C#代碼示例
TmcClient client = new TmcClient("app_key", "app_secret", "default"); client.Connect("ws://mc.api.taobao.com/"); for (int i = 0; i < 10; i++) { client.Send("helloworld-topic", "{helloworld-content}", "session_key"); }
常用消息類型說明
平臺已經(jīng)提供結(jié)構(gòu)化的消息說明文檔,點擊這里進(jìn)入消息文檔,您也可以進(jìn)入控制臺的消息服務(wù)里面進(jìn)行訂閱和取消訂閱。
沙箱消息服務(wù)開通
一、訪問http://mini.tbsandbox.com/,登錄沙箱【沙箱賬號可以自己注冊或者使用默認(rèn)賬號參見 http://www.tbsandbox.com/doc/的“測試帳號創(chuàng)建”介紹】
二、選擇沙箱測試工具-消息通道管理
輸入沙箱apppkey訂閱消息【沙箱測試以測試商品庫存修改為例訂閱taobao_item_ItemStockChanged】
三、沙箱獲取SessionKey快捷操作,輸入沙箱AppKey點擊搜索獲取SessionKey。如下圖表示sandbox_c_1授權(quán)1021719331這個應(yīng)用可以獲取它的數(shù)據(jù),授權(quán)碼為SessionKey對應(yīng)的值。然后再調(diào)用taobao.tmc.user.permit接口表示授權(quán)1021719331接收它的消息。
四、代碼運行(請求到ws://mc.api.tbsandbox.com/,使用沙箱appkey、secret、沙箱賬號,代碼部分參考以上正式環(huán)境)起來以后可到沙箱 賣家中心 修改庫存測試驗證。
消息服務(wù)常見問題
什么是分組,是否需要分組
消息分組是用戶消息隔離的一種方式,組內(nèi)用戶的消息只會發(fā)送到相同組名的連接上。同一個組支持多個連接,同一組的消息,隨機(jī)發(fā)送到組內(nèi)的某一個連接。如果要用戶的類型對消息區(qū)別對待,比如優(yōu)先保證付費用戶,然后再保證免費用戶,就可以通過消息分組來接收不同用戶的消息。每個應(yīng)用最多創(chuàng)建50個分組,每個分組用戶數(shù)不限。
什么是多連接接收消息,如何建立多個連接
多連接收消息是指同一分組內(nèi)ISV服務(wù)器與TOP的消息服務(wù)器建立多個連接來收消息。多鏈接是對同一個分組而言,消息在下發(fā)時隨機(jī)選擇從分組內(nèi)的多個連接中選擇一個連接下發(fā)消息。多鏈接有的隨機(jī)下發(fā)消息的功能,可以用同一分組多連接來實現(xiàn)集群,負(fù)載功能。
建立多鏈接只需要用相同的代碼重新啟動一個TmcClient實例??稍谕粋€ISV服務(wù)器上,也可在不同的ISV服務(wù)器上,建立同一個分組的多鏈接。
什么情況下使用多連接
消息服務(wù)的服務(wù)端有消息堆積的功能,它看的是你客戶端的處理能力,只要能處理他就給你發(fā),處理不了就堆積在服務(wù)端,一般情況下不需要建立多連接,單個連接就能把機(jī)器的網(wǎng)卡跑滿。新消息服務(wù)的多連接,更多的是應(yīng)用在用戶分組,或者做集群部署的場景下。
消息重發(fā)邏輯是怎么樣的
對 于斷開連接(如應(yīng)用掛了)情況,服務(wù)端會堆積消息,等應(yīng)用重新連接進(jìn)來后,再把堆積的消息順序推送給客戶端。一條消息從誕生開始,如果應(yīng)用一直不接收,服 務(wù)端最長保留時間為3天,超過3天會自動清除。對于連接正常,但消息處理失敗的情況,服務(wù)端會最快隔10分鐘進(jìn)行第一次重發(fā),如果應(yīng)用一直處理失敗,服務(wù) 端會一直定時重發(fā),直到消息被清理為止。
PHP中json_decode整形溢出問題
PHP 5.3版本以下,json_decode依賴于操作系統(tǒng)的位數(shù)來解釋數(shù)字,在32位系統(tǒng)上最大只支持2^32的數(shù)字解釋,在64位的系統(tǒng)上最大支持 2^64的數(shù)字的解釋。由于消息服務(wù)的消息ID超過32位系統(tǒng)的最大值,如果沒有升級到PHP 5.3版本以上,就會由于確認(rèn)了錯誤的消息ID,導(dǎo)致消息重復(fù)投遞。解決方案是:1. 升級PHP到5.3以上;2. 把應(yīng)用部署到64位的系統(tǒng)上;3. 把JSON消息里面的數(shù)字通過正則等手段替換為字符串。
消息的斷開和心跳測試
客戶端要直接斷開消息:TmcClient.close(); 心跳測試是否正常連接:TmcClient.isOnline();
天貓退款和淘寶退款的區(qū)別
天貓退款只包含天貓的訂單,淘寶退款包含淘寶和天貓的訂單,不過天貓退款的狀態(tài)有豐富一點,多了一些過程。如果用不到,建議用淘寶退款消息就可以了,如果需要,需要申請?zhí)熵埻丝預(yù)PI權(quán)限,申請后即可開通。
消息服務(wù)會有延時嗎
為用戶開通消息服務(wù)taobao.tmc.user.permit后需要10秒才能生效。使用中消息基本沒有延遲,都會在1秒內(nèi)收到。如果有消息堆積或者程序處理不及時,就會有延時。延時時間與程序處理能力有關(guān)。為用戶取消消息服務(wù)taobao.tmc.user.cancel后1秒內(nèi)生效,取消后,堆積的消息會繼續(xù)發(fā)送,新的消息不會發(fā)送。
商品消息message.getContent()中的nick為空正常嗎?我怎么判斷該消息屬于哪個店鋪?
商品消息中,是有nick為空的情況的??梢杂脗€外層獲取到message.getUserNick()或message.getUserId()。
消息服務(wù),用戶到期了,消息還會不會收到?
消息服務(wù)推送的判斷有兩個條件:1、是用戶授權(quán)是否在有效期內(nèi);2、是用戶有沒有開通消息服務(wù)(toabao.tmc.user.permit)。只有二者同時滿足才會推送。相反如果用戶授權(quán)到期就不會推送。另外用戶授權(quán)到期一個月以內(nèi),用戶的開通關(guān)系還會保存,一個月以后會清除。如果在一個月以內(nèi)用戶重新授權(quán),就不需要重新為用戶開通消息服務(wù)。
獲取消息后,如果不確認(rèn),消息服務(wù)會選擇時機(jī)重發(fā),重發(fā)次數(shù)由消息服務(wù)控制,目前會重發(fā)多少次?
消息服務(wù)每十分鐘查一次未處理的消息,然后擇機(jī)發(fā)送,如果消息3天內(nèi)都沒有被確認(rèn)將會被刪除
消息沒有收到,如何確認(rèn)是不是消息服務(wù)漏掉了?
通過日常反饋,未出現(xiàn)消息服務(wù)漏消息的情況,一般是ISV程序處理未收到消息或者程序處理能力導(dǎo)致消息阻塞。排查消息可以從以下方面確認(rèn):
* 首先確認(rèn)授權(quán)(SessionKey)是否有效;
* 調(diào)用taobao.tmc.user.get確認(rèn)當(dāng)前用戶以及開通的消息,返回參數(shù)傳入topics;調(diào)用TmcClient.isOnline()測試心跳是否正常連接。若以上排查不出結(jié)果可以提交問題到支持中心附上:AppKey、用戶nick、消息狀態(tài)、消息大概時間、訂單的tid、商品的num_iid。
客戶端配置參數(shù)注意事項
.NET SDK:ReconnectIntervalSeconds重連時間,標(biāo)識TmcClient斷開時重連的時間間隔。此值必須>10s,如果此值太小會出現(xiàn)鏈接不上的情況,原因是服務(wù)端如果檢測到500ms內(nèi)重連,會斷開新的鏈接。
商品庫存變更注意事項
- 當(dāng)通過API(taobao.item.quantity.update,或taobao.item.sku.update更改數(shù)量) 修改商品庫存時,會產(chǎn)生taobao_item_ItemStockChanged的消息。
- 當(dāng)通過API(taobao.item.update)更新商品數(shù)量時 或 通過頁面修改商品庫存時,只會產(chǎn)生消息商品變更消息(taobao_item_ItemUpdate),而不會發(fā)taobao_item_ItemStockChanged消息,消息只包含商品庫存數(shù)量,無變化量。
下面的操作中,是直接返回商品的庫存數(shù)量:
- 當(dāng)商品拍下(拍下減庫存)或付款(付款減庫存)(包含通過API創(chuàng)建交易)時,會產(chǎn)生上面的消息。
- 當(dāng)訂單關(guān)閉或子訂單關(guān)閉會產(chǎn)生此消息(包含通過API關(guān)閉交易)。
- 當(dāng)買家付完款后,賣家通過頁面修改訂單商品的SKU時,相應(yīng)的商品的SKU庫存也會變化,產(chǎn)生上面的消息(此時還會產(chǎn)生交易變更消息taobao_trade_TradeChanged)。
退款相關(guān)消息說明
通過接口taobao.trade.fastrefund(快速退款)退款時不會產(chǎn)生退款相關(guān)的消息,要有退款流程的退款才會產(chǎn)生退款相關(guān)的消息??焖偻丝罱涌冢╰aobao.trade.fastrefund)直接打款給買家,然后關(guān)閉交易,不會創(chuàng) 建退款流程,所以不會產(chǎn)生退款消息。目前只有虛擬類目才支持taobao.trade.fastrrefund接口。
time 、outtime、localtime消息相關(guān)字段說明
- time 是消息產(chǎn)生時間
- outtime 是消息的本次推送時間
- localtime 是本機(jī)的時間
- outtime - time 表示服務(wù)端的處理或重發(fā)延遲時長
- localtime - outtime 表示本機(jī)的時間與TOP時間差,或網(wǎng)絡(luò)延遲,或收到消息后處理的延遲
消息服務(wù)報錯isp.system-error: unknown errors,isv.tmc-switch-off: appkey,the app do not enable messaging-channel feature
應(yīng)用未訂閱(開通)消息服務(wù),就使用TmcClient來接收消息。
FAQ
- 關(guān)于此文檔暫時還沒有FAQ