平台技術-訊息服務使用介紹


訊息服務是開放平台為提高應用API呼叫效率而推出的一種主動推播服務( From淘寶 ),推播內容包含(淘寶交易、商品、退款等資訊) ,基於此推播服務,應用程式取得淘寶資料不需再不停輪詢API,僅需在接收到淘寶推送的訊息時呼叫API取得即可,大幅提高API呼叫效率和降低API使用費用。同時也提供訊息回流服務( To淘寶 ),應用可將訊息回流到淘寶,做商品數源服務等。

From淘寶:即淘寶向外推送淘寶(包括天貓)的交易、商品、退款等官方訊息。

To淘寶:即向淘寶回流訊息。

那麼如何使用訊息服務呢?請看以下是訊息服務 From淘寶 和 To淘寶 兩種方式的詳細使用說明。

From淘寶訊息服務使用

image

應用程式訂閱訊息

進入ISV控制台,在「應用程式管理->訊息服務->訂閱訊息」頁面,選擇需要的訊息進行訂閱,點選對應訊息後面的「訂閱」即可

image

訂閱訊息成功,可以在「我的訂閱」中查看已經成功訂閱的訊息。如果需要取消訊息的訂閱,直接點擊 「取消訂閱」。點擊訊息名稱可以查看每個訊息返回的詳細欄位資訊。

image

注意:如果該訊息沒有權限,則表示應用未開通相關API呼叫權限,透過點擊“申請權限”,進入申請對應的權限套件。另如果需要在沙箱開通訊息服務使用,可參考本文的[沙箱訊息服務開通]章節

#給用戶開通訊息

呼叫taobao .tmc.user.permit介面給用戶(即淘寶或天貓商家)開通,可以選擇只給用戶開通部分訊息類型,也可全部開通。具體可看該API 入參說明。

備註:

  • 給使用者開通訊息前提是使用者已經給應用程式授權,如未授權,請參考取得使用者授權說明。
  • 取消使用者的訊息服務呼叫taobao.tmc.user.cancel介面。
  • 可以透過介面taobao.tmc.user.get取得使用者已開通訊息,入參必須輸入is_valid,topics,modified來判斷使用者授權訊息是否成功
  • 訊息服務API文件:點擊這裡查看

程式碼實作接收訊息

#正式環境服務位址:ws://mc.api.taobao.com/
沙箱環境服務位址:ws://mc.api.tbsandbox.com/
接收訊息,實作方式有兩種:透過SDK接收訊息透過API接收訊息 ,推薦採用SDK接收訊息。

透過SDK接收訊息

目前支援JAVA與.NET語言,其它語言建議採用API接收訊息。透過SDK接收訊息只需要專注於業務的處理,不需要操心訊息重發、確認、長連線的重連等操作,SDK會自動處理好一切。

JAVA介面使用說明

public interface MessageHandler {
 
    /**
     * 消息通道客户端收到消息后,会回调该方法处理具体的业务,处理结果可以通过以下两种方式来表述:
     * <ul>
     * <li>抛出异常或设置status.fail()表明消息处理失败,需要消息通道服务端重发
     * <li>不抛出异常,也没有设置status信息,则表明消息处理成功,消息通道服务端不会再投递此消息
     *
     * @param message 消息内容
     * @param status 处理结果,如果调用status.fail(),消息通道将会择机重发消息;否则,消息通道认为消息处理成功
     * @throws Exception 消息处理失败,消息通道将会择机重发消息
     */
    public void onMessage(Message message, MessageStatus status) throws Exception;
 
}

JAVA使用程式碼範例

TmcClient client = new TmcClient("app_key", "app_secret", "default"); // 关于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(); // 消息处理失败回滚,服务端需要重发
          // 重试注意:不是所有的异常都需要系统重试。
          // 对于字段不全、主键冲突问题,导致写DB异常,不可重试,否则消息会一直重发
          // 对于,由于网络问题,权限问题导致的失败,可重试。
          // 重试时间 5分钟不等,不要滥用,否则会引起雪崩
        }
    }
});
client.connect("ws://mc.api.taobao.com"); // 消息环境地址:ws://mc.api.tbsandbox.com/
「附註:採用Java main方法在Eclipse裡面執行上面的程式碼測試時,請在client.connect()後面加上Thread.sleep讓main執行緒等待一段時間結束,以便觀察訊息的即時接收情況,否則main執行緒結束後,TMC長連線也會跟著斷開。如果是在web伺服器上執行上面的程式碼,則不用在client.connect()後面加任何Thread.sleep程式碼,也不需要在外麵包一層while(true)循環,因為web伺服器上的主執行緒只要伺服器不關閉都是不會結束的,TMC的長連線會一直維持。

C#使用範例程式碼

TmcClient client = new TmcClient("appkey", "appsecret", "default"); // 关于default参考消息分组说明
client.OnMessage += (s, e) =>
{
    try
    {
        Console.WriteLine(e.Message.Topic);
        Console.WriteLine(e.Message.Content);
        // 默认不抛出异常则认为消息处理成功
    }
    catch (Exception exp)
    {
        Console.WriteLine(exp.StackTrace);
        e.Fail(); // 消息处理失败回滚,服务端需要重发
        // 重试注意:不是所有的异常都需要系统重试。 
        //对于字段不全、主键冲突问题,导致写DB异常,不可重试,否则消息会一直重发
        // 对于,由于网络问题,权限问题导致的失败,可重试。
        // 重试时间 5分钟不等,不要滥用,否则会引起雪崩
    }
};
client.Connect("ws://mc.api.taobao.com/"); // 消息环境地址:ws://mc.api.tbsandbox.com/
附註: 採用C# Main方法在VS控制台工程裡面執行上面的程式碼測試時,請在client.Connect後面加上Console.Read()或Thread.Sleep讓main執行緒暫時不結束,以便觀察訊息的即時接收狀況,否則Main執行緒結束後,TMC長連線也會跟著斷開。如果是在IIS伺服器或C#應用程式裡面執行上面的程式碼,則不用在client.Connect後面加任何等待的程式碼,也不需要在外麵包一層while(true)循環,只要保持IIS伺服器或C#應用程式不關閉,TMC的長連線會一直維持。

透過API接收訊息

提供API接收訊息的目的是那種對多執行緒和長連線處理不方便的語言使用的,例如PHP、Python,這些語言官方暫時沒有提供SDK,可以透過下面兩個API配合使用也能達到接收和確認訊息的目的。建議盡量用SDK方式,如果必須使用API​​,建議呼叫taobao.tmc.messages.consume介面時盡量不要並發或併發量不要太大,API使用存在實時性不是很高的情況,如果實時性要求高建議還是用SDK。

基本步驟:

  • 首先消費訊息:API名稱:taobao.tmc.messages.consume訊息消費後,指標自動後移,下次調用自動取得到未消費過的訊息,但是消費確認後的訊息無法再取得。
  • 然後確認訊息:API名稱:taobao.tmc.messages.confirm取得訊息後,如果不確認,訊息服務會選擇時機重發,重發次數由訊息服務控制,如果訊息3天內都沒有被確認將會被刪除。

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在網路好的情況下能達到10毫秒左右,每次消費得到的消息為空時,務必暫停至少1秒才去執行下一次循環拉取訊息,否則會產生很多無謂的請求,白白浪費服務端的資源,以及應用自身的API流量包。

訊息分組使用介紹

使用者數量很大需要多台機器組成一個叢集來接收訊息,或是對商家進行隔離獨立接收訊息的時候。不管是SDK還是API都可以透過多連線接收訊息。

訊息服務支援多重連線有兩種方式:Ⅰ、建立多個使用者分組,每個使用者分組建立一個連線。 Ⅱ、同一個分組建立多個連線

  • 建立分組:呼叫介面taobao.tmc.group.add建立自訂分組。附註:訊息服務會為應用程式建立default分組,沒有指派到指定分組【group】的使用者都屬於default分組,透過SDK或API消費訊息時,如果不指定分組,就表示採用預設分組連線。
  • 刪除分組:呼叫介面taobao.tmc.group.delete刪除指定的分組或分組下的使用者。註:每個應用程式最多建立50個分組,每個分組使用者數不限。

To淘寶訊息服務使用

LB1n7l2LpXXXXXkXFXXXXXXXXXX.png

#訂閱資料回傳訊息

在應用程式管理後台,點擊“訂閱訊息”,如果該訊息沒有權限,則透過點擊“申請權限”,進入申請相應的增值包

LB1l58TLpXXXXXrXVXXXXXXXXXX.png

##代碼實現推送訊息

對於訊息的回傳,有兩種方式:

透過API發布訊息透過SDK發布訊息 ,建議採用API發布訊息。

透過API發布訊息

具體使用說明,請參考API文件:

taobao.tmc.message.produce

透過SDK發布訊息(不建議)

目前支援JAVA與.NET語言,其它語言建議採用API發布訊息。

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");
}

常用訊息類型說明

平台已經提供結構化的訊息說明文檔,點擊這裡進入

訊息文檔,您也可以進入控制台的訊息服務裡面進行訂閱和取消訂閱。

沙箱訊息服務開通

一、造訪

http://mini.tbsandbox.com/,登入沙箱【沙箱帳號可以自己註冊或使用默認帳號請參考http://www.tbsandbox.com/doc/的「測試帳號建立」介紹】

二、選擇沙箱測試工具-訊息通道管理

LB1c9abLpXXXXaaXXXXXXXXXXXX.png

輸入沙箱apppkey訂閱訊息【沙箱測試以測試商品庫存修改為例訂閱taobao_item_ItemStockChanged】

LB1t1V5LpXXXXbvXpXXXXXXXXXX.png

三、沙箱取得SessionKey快速操作,輸入沙箱AppKey點選搜尋取得SessionKey。如下圖表示sandbox_c_1授權1021719331這個應用程式可以取得它的數據,授權碼為SessionKey對應的值。然後再呼叫taobao.tmc.user.permit介面表示授權1021719331接收它的訊息。

LB1WMRNLpXXXXcXXVXXXXXXXXXX.png

四、程式碼執行(要求到ws://mc.api.tbsandbox.com/,使用沙箱appkey、secret、沙箱帳號,程式碼部分參考以上正式環境)起來以後可到沙箱賣家中心修改庫存測試驗證。

訊息服務常見問題

什麼是分組,是否需要分組
訊息分組是使用者訊息隔離的一種方式,群組內使用者的訊息只會發送到相同組名的連線。同一個組支援多個連接,同一組的消息,隨機發送到組內的某一個連接。如果要用戶的類型對訊息區別對待,例如優先保證付費用戶,然後再保證免費用戶,就可以透過訊息分組來接收不同用戶的訊息。每個應用程式最多建立50個分組,每個分組使用者數不限。

什麼是多連線接收訊息,如何建立多個連線
多重連線收訊息是指同一分組內ISV伺服器與TOP的訊息伺服器建立多個連線來收訊息。多連結是對同一個分組而言,訊息在下發時隨機選擇從分組內的多個連接中選擇一個連接下發送訊息。多連結有的隨機下發訊息的功能,可以用同一分組多連接來實現集群,負載功能。

建立多重連結只需要用相同的程式碼重新啟動一個TmcClient實例。可在同一個ISV伺服器上,也可在不同的ISV伺服器上,建立同一個分組的多重連結。

什麼情況下使用多連線
訊息服務的服務端有訊息堆積的功能,它看的是你客戶端的處理能力,只要能處理他就給你發,處理不了就堆積在服務端,一般情況下不需要建立多連接,單一連接就能把機器的網卡跑滿。新訊息服務的多連接,更多的是應用在用戶分組,或是做集群部署的場景下。

訊息重發邏輯是怎麼樣的
對於斷開連接(如應用掛了)情況,服務端會堆積訊息,等應用重新連接進來後,再把堆積的訊息順序推播給客戶端。一則訊息從誕生開始,如果應用程式一直不接收,服 務端最長保留時間為3天,超過3天會自動清除。對於連線正常,但訊息處理失敗的情況,服務端會最快隔10分鐘進行第一次重發,如果應用一直處理失敗,服務 端會一直定時重發,直到訊息被清理為止。

PHP中json_decode整形溢出問題
PHP 5.3版本以下,json_decode依賴作業系統的位數來解釋數字,在32位元系統上最大隻支援2^32的數字解釋,在64位的系統上最大支持2^64的數字的解釋。由於訊息服務的訊息ID超過32位元系統的最大值,如果沒有升級到PHP 5.3版本以上,就會因為確認了錯誤的訊息ID,導致訊息重複投遞。解決方案是:1. 升級PHP到5.3以上;2. 把應用部署到64位元的系統上;3. 把JSON訊息裡面的數字透過正規等手段替換為字串。

訊息的斷開和心跳測試
客戶端要直接斷開訊息:TmcClient.close(); 心跳測試是否正常連線:TmcClient.isOnline();

天貓退款和淘寶退款的區別
天貓退款只包含天貓的訂單,淘寶退款包含淘寶和天貓的訂單,不過天貓退款的狀態有豐富一點,多了一些過程。如果用不到,建議用淘寶退款訊息就可以了,如果需要,需要申請天貓退款API權限,申請後即可開通。

訊息服務會有延遲嗎
為用戶開通訊息服務taobao.tmc.user.permit後需要10秒才能生效。使用中訊息基本上沒有延遲,都會在1秒內收到。如果有消息堆積或程序處理不及時,就會有延遲。延時時間與程序處理能力有關。為用戶取消訊息服務taobao.tmc.user.cancel後1秒內生效,取消後,堆積的訊息會繼續發送,新的訊息不會發送。

商品訊息message.getContent()中的nick為空正常嗎?我要怎麼判斷該訊息屬於哪個店?
商品訊息中,是有nick為空的情況的。可以用個外層取得到message.getUserNick()或message.getUserId()。

訊息服務,用戶到期了,訊息還會不會收到?
訊息服務推送的判斷有兩個條件:1、是使用者授權是否在有效期限內;2、是使用者有沒有開通訊息服務(toabao.tmc.user.permit)。只有二​​者同時滿足才會推送。相反如果用戶授權到期就不會推送。另外用戶授權到期一個月以內,用戶的開通關係還會保存,一個月以後會清除。如果在一個月以內用戶重新授權,就不需要重新為用戶開通訊息服務。

取得訊息後,如果不確認,訊息服務會選擇時機重發,重發次數由訊息服務控制,目前會重發多少次?
訊息服務每十分鐘查一次未處理的訊息,然後擇機發送,如果訊息3天內都沒有被確認將會被刪除

訊息沒有收到,如何確認是不是訊息服務漏掉了?
透過日常回饋,未出現訊息服務漏訊息的情況,一般是ISV程式處理未收到訊息或程式處理能力導致訊息阻塞。排查訊息可以從以下方面確認:
* 先確認授權(SessionKey)是否有效;
* 呼叫taobao.tmc.user.get確認目前使用者以及開通的訊息,傳回參數傳入topics;呼叫TmcClient. isOnline()測試心跳是否正常連接。若以上排查不出結果可以提交問題到支援中心附上:AppKey、使用者nick、訊息狀態、訊息大概時間、訂單的tid、商品的num_iid。

客戶端設定參數注意事項
.NET SDK:ReconnectIntervalSeconds重連時間,識別TmcClient斷開時重連的時間間隔。此值必須>10s,如果此值太小會出現連結不上的情況,原因是服務端如果偵測到500ms內重連,會中斷新的連結。

商品庫存變更注意事項

  • 當透過API(taobao.item.quantity.update,或taobao.item.sku.update更改數量) 修改商品庫存時,會產生taobao_item_ItemStockChanged的訊息。
  • 透過API(taobao.item.update)更新商品數量或透過頁面修改商品庫存時,只會產生訊息商品變更訊息(taobao_item_ItemUpdate),而不會發送taobao_item_ItemStockChanged訊息,訊息只包含商品庫存數量,無變化量。

在下面的操作中,是直接返回商品的庫存數量:

  • 當商品拍下(拍下減庫存)或付款(付款減庫存)(包含透過API建立交易)時,會產生上面的訊息。
  • 當訂單關閉或子訂單關閉會產生此訊息(包含透過API關閉交易)。
  • 當買家付完款後,賣家透過頁面修改訂單商品的SKU時,對應的商品的SKU庫存也會變化,產生上面的訊息(此時也會產生交易變更訊息taobao_trade_TradeChanged)。

退款相關訊息說明
透過介面taobao.trade.fastrefund(快速退款)退款時不會產生退款相關的訊息,要有退款流程的退款才會產生退款相關的訊息。快速退款介面(taobao.trade.fastrefund)直接打款給買家,然後關閉交易,不會創 建退款流程,所以不會產生退款訊息。目前只有虛擬類別目才支援taobao.trade.fastrrefund介面。

time 、outtime、localtime訊息相關欄位說明

  • time 是訊息產生時間
  • outtime 是訊息的本次推送時間
  • localtime 是本機的時間
  • outtime - time 表示服務端的處理或重發延遲時長
  • localtime - outtime 表示本機的時間與TOP時間差,或網路延遲,或收到訊息後處理的延遲

訊息服務報錯isp.system-error: unknown errors,isv.tmc-switch-off: appkey,the app do not enable messaging-channel feature
#應用未訂閱(開通)訊息服務,就使用TmcClient來接收訊息。

FAQ

  • 關於此文件暫時還沒有FAQ
#