LINE Engineering
Blog

開發LINE聊天機器人不可不知的十件事

Augustin Wang 2017.08.01

LINE台灣首席應用分析師,負責LINE平台產品的技術與應用研發。

LINE於2016年9月推出Messaging API之後,越來越多開發者投入心力設計各式各樣功能的LINE聊天機器人。然而,撰寫一個LINE聊天機器人除了要有好的應用情境之外,資訊技術上還必須注意一些重要的細節,以免設計出來的聊天機器人上線後無法正常運作。本文分享了作者自身與協助客戶或合作夥伴開發各種LINE聊天機器人所觀察到常見的問題與建議的處理方式,提供給LINE聊天機器人開發者作為參考。

第一件事:正確設定HTTPS

基於資料通訊安全的因素,在LINE平台上開發應用服務的所有資料傳送都必須透過加密通道。因此,當開發者架設LINE Messaging APIWebhook伺服器時,一定要使用HTTPS通訊協定。

在設定HTTPS伺服器時,有下列幾點必須注意的事項:

  1. HTTPS伺服器所使用的根憑證Root CA)必須是在LINE平台的白名單列表中,否則LINE平台會拒絕傳送訊息。在白名單列表中大多數的憑證都需要付費申請,但是LINE平台也支援常用的免費憑證,例如Let’s Encrypt
  2. 請勿使用已知具有安全性漏洞的協定(例如SSL v2或SSL v3)或Cipher Suite(例如SWEET32或CVE-2016-2183)。
  3. 請務必正確設定中繼憑證Intermediate certificate),以避免無法對應到根憑證而發生錯誤。這是最常見的問題通報狀況,請在設定HTTPS伺服器時多加留意。

如果HTTPS伺服器沒有正確設定成功,Webhook程式將無法收到LINE平台的任何事件訊息,並且管理者們會收到來自LINE平台的警示電子郵件,內容的錯誤原因會顯示「UNCLASSIFIED」。建議開發者在設定完成HTTPS伺服器之後,立即使用一些免費工具進行檢查,以確保HTTPS伺服器的可用性。這些免費工具舉例如下:

  • Qualys SSL Labs
  • testssl.sh
  • DigiCert SSL Installation Diagnostics Tool
  • 第二件事:驗證訊息來源

    當開發者的Webhook伺服器收到以POST方式所傳送的LINE事件訊息時,必須要立即驗證該事件訊息是否真的來自LINE平台,以避免被偽造的訊息所欺騙造成資訊安全危機。標準的驗證方式是檢查所收到HTTP請求標頭(HTTP request header)中的數位簽章。如果該HTTP POST訊息是來自LINE平台,在HTTP請求標頭中一定會包括X-Line-Signature項目,該項目的內容值是即為數位簽章。例如:

    POST /callback HTTP/1.1
    X-Line-Signature: j9p1sXsb0yCyIEE8cEsmHbp9eHc85P2DQBVH1RKiQLk=
    Content-Type: application/json;charset=UTF-8
    Content-Length: 223
    Host: callback.sample.com
    Accept: */*
    User-Agent: LineBotWebhook/1.0
    
    {"events":[{"type":"message","replyToken":"1234567890abcdef1234567890abcdef","source":{"userId":"U1234567890abcdef1234567890abcdef","type":"user"},"timestamp":1500052665000,"message":{"type":"audio","id":"1234567890123"}}]}
    

    驗證方式如下:

    1. 以Channel secret作為密鑰(Secret key),使用HMAC-SHA256演算法取得HTTP請求本體(HTTP request body)的文摘值(Digest value)。
    2. 將上述文摘值以Base64編碼,比對編碼後的內容與X-Line-Signature項目內容值是否相同;若是相同,表示該事件訊息是來自LINE平台,否則拒絕處理該事件訊息。

    有些企業希望將LINE平台傳送事件訊息所使用的IP位址設定在該企業網路防火牆(Firewall)設備的白名單中,以阻擋非合法來源的HTTP請求;然而LINE平台傳送事件訊息所使用的IP位址並非一直維持固定範圍,很可能會視實際需求進行調整,有任何變更也難以主動通知所有開發者,因此不建議採用此種驗證方式。

    第三件事:盡快回覆LINE平台正確的HTTP狀態碼

    不少開發者的程式撰寫方式是在接收到LINE平台的事件訊息之後就立刻進行整個事件處理流程,直到處理完成並回覆發訊者之後,才回覆LINE平台並關閉HTTP連線。然而,LINE平台在傳送事件訊息到開發者Webhook伺服器之後,若是等待10秒鐘沒有得到任何HTTP狀態碼的回覆,就會發生逾時(Timeout)錯誤,LINE平台會關閉該次HTTP連線並認為該次傳送結果失敗;若是一直發生傳送失敗的狀況,LINE平台可能會將該Webhook伺服器封鎖或進行其他處置,造成開發者的應用服務無法正常運作。

    如果是LINE Business Connect帳號的開發者,LINE平台在偵測到逾時錯誤後,會嘗試重送數次,但是實際上該事件訊息已經被處理過,所以會發生同一個事件被多次處理的嚴重問題。因此,如果無法確定事件處理時間加上網路傳輸時間可以在10秒鐘內完成,正確的做法應該是在Webhook收到事件訊息並驗證訊息來源與內容無誤之後,立即回覆LINE平台HTTP狀態碼200並關閉該HTTP連線,再來處理該事件訊息與回覆發訊者。

    一般而言,開發者可以使用下列二種方式來進行收到LINE事件訊息後的非同步處理:

  • 在Webhook收到事件訊息的程序上,先回覆LINE平台HTTP狀態碼200並關閉連線,然後以原程序直接處理。
  • Webhook收到事件訊息的程序先將事件內容儲存到一個佇列(Queue)或資料庫中,然後回覆LINE平台HTTP狀態碼200並關閉連線,結束程序。再以另外一個或多個程序依序讀取佇列或資料庫中的事件內容逐一處理。
  • 第四件事:LINE平台所傳送的事件是一個陣列

    這是初學LINE聊天機器人的開發者易犯的一個錯誤。可能是因為全新的Messaging API帳號沒有大量的事件訊息傳入,每次所收到事件幾乎都只有一筆資料,所以開發者會誤以為每個事件訊息只需要處理一筆資料。事實上,LINE平台傳送給Webhook伺服器的HTTP請求本體是包括一個或多個Webhook事件物件的JSON格式物件,例如:

    {
      "events": [
        {
          "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
          "type": "message",
          "timestamp": 1462629479859,
          "source": {
            "type": "user",
            "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
          },
          "message": {
            "id": "325708",
            "type": "text",
            "text": "Hello, world"
          }
        },
        {
          "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
          "type": "follow",
          "timestamp": 1462629479859,
          "source": {
            "type": "user",
            "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
          }
        }
      ]
    }
    

    在處理LINE平台的事件請求時,必須以迴圈方式逐一讀取與處理每一個Webhook事件物件,而不是在處理完第一筆資料後便停止了。而同一次收到的LINE平台事件請求中的每一個Webhook事件物件是可以來自不同的LINE使用者的不同事件內容,開發者應該將每個事件訊息都當作獨立個體進行處理。

    第五件事:瞭解用戶識別碼

    每一個LINE用戶帳號都有一個專屬的內部識別碼,稱為User ID。User ID與LINE用戶自訂的LINE ID的格式與用途完全不同。開發Messaging API應用程式時,無論是接受訊息、傳送訊息、或是存取其他API,皆必須使用User ID來代表LINE用戶。User ID的格式為33個字元的英數字字串,例如U206d25c2ea6bd87c17655609a1c37cb8。如果開發者想要驗證一個字串是否為正確的User ID格式,可以使用正規表示式Regular Expression)「^U[0-9a-f]{32}$」來測試。

    User ID的特色就是每一個LINE用戶在每一個公司/組織的LINE平台開發帳號都有該公司/組織專屬的識別碼,也就是相同公司/組織下的每個Messaging API帳號聯繫相同的LINE用戶會使用一樣的User ID,而不同公司/組織的Messaging API帳號聯繫相同的LINE用戶就必須使用各自不同的User ID。如此確保每一個公司/組織都無法取得或使用其他公司/組織專屬的User ID,保障公司/組織與LINE用戶的隱私安全。

    第六件事:使用Reply Token的注意事項

    LINE Messaging API的Webhook的下列事件物件會帶有Reply token:message、follow、join、postback與beacon。使用Reply token傳送訊息請注意以下二點:

    1. Reply token的有效期間非常短,在收到Webhook事件後必須盡快使用。有效期間會隨著系統狀況而調整,所以我們也不便對外提供精確的數字。可以確定的是這個數字會以秒為單位,開發者是無法以Reply token回覆需要經過數分鐘以上處理時間才能獲得結果的訊息。這個目的是希望開發者能夠在最短的時間內回覆用戶的訊息,提供更好的使用者體驗。
    2. Reply token僅可以使用一次,如果有需要在收到Webhook事件後分多次回覆,就必須使用Push message的方式來傳送訊息。

    第七件事:注意Imagemap Message與Template Messages的使用者體驗

    Imagemap message以及Template messages有個特色:只要該訊息還在對話歷史紀錄中,用戶隨時都可以點擊該訊息上的連結產生對應的動作。如果開發者設定點擊連結的動作是幫用戶送出特定字串訊息,那麼一定要確定這個特定訊息在任何時候都會以相同的方式處理。以下舉例說明:

    聊天機器人送出一個Template message詢問用戶要輸入哪個項目,用戶點擊了「姓名」,產生的對應動作是幫用戶送出「姓名」字串,聊天機器人收到關鍵字「姓名」之後便請用戶輸入姓名,並且預期接下來收到的字串是用戶的姓名。然而,用戶其實想要輸入地址資料,並且已經開始撰寫地址字串。此時,用戶發現點擊了錯誤的選項,最直覺的想法就是點擊「地址」以變更聊天機器人所預期下一個會收到的項目為地址。結果:

    從上一個畫面可以發現:Template message再次被點擊時,會執行原始定義的動作,而不檢查聊天機器人或用戶目前的狀態。當「地址」項目被點擊後,產生的對應動作是幫用戶送出「地址」字串,但是聊天機器人認為用戶送上來的字串是代表姓名,因此就將「地址」設定為用戶的姓名。可能有開發者會提出:聊天機器人應該要把「地址」當作關鍵字判斷,收到這個關鍵字之後就改變預期所收到的下一個項目。然而,萬一有位用戶的姓名真的叫做「地址」呢?這樣該用戶就完全無法輸入姓名了!相同的狀況也會發生在Imagemap message與圖文訊息選單(Rich menu)上,原因都是點擊動作幫用戶所產生的字串與一般對話訊息混淆,造成用戶點擊時所期待的行為沒有被正確處理。

    要解決訊息混淆的問題,最根本的方式就是讓Imagemap message或Template messages的點擊動作所產生的反應具有獨特性,聊天機器人的程式就能確認這個反應一定是來自於點擊行為,而非用戶輸入。例如在Template messages的使用上盡量採取Postback作為回應方式,如果非得要使用Message型態回應,這個回應所產生的字串必須要是用戶在正常情況下不會輸入的樣貌,才能有助於以程式判斷。以上述畫面為例,當用戶點擊「地址」所產生的字串是「[TemplateMsg][【地址】]」而非「地址」的話,聊天機器人就可以很容易偵測到發生點擊動作而正確地變更輸入項目,如下圖所示:

    第八件事:傳送檔案給用戶時,用戶設備會直接存取原始檔案所在的網路伺服器

    在LINE Messaging API中,當傳送訊息給用戶時,有部分的Send message object會包括檔案連結的網址,例如image、video、audio、imagemap message或template message等。

    {
        "type": "image",
        "originalContentUrl": "https://example.com/original.jpg",
        "previewImageUrl": "https://example.com/preview.jpg"
    }
    
    
    {
        "type": "video",
        "originalContentUrl": "https://example.com/original.mp4",
        "previewImageUrl": "https://example.com/preview.jpg"
    }
    
    {
        "type": "audio",
        "originalContentUrl": "https://example.com/original.m4a",
        "duration": 240000
    }
    

    當LINE用戶的設備(例如手機或個人電腦)收到image、video、audio、imagemap message或template message等訊息時,會直接存取開發者所設定的網址。因此若是此類訊息傳送給大量的LINE用戶,則會有大量的設備存取開發者所設定的網路伺服器,可能會造成該伺服器的網路雍塞或是系統無法負荷。如果開發者有發送此類訊息的需求時,請將這些檔案放置於內容遞送網路(Content delivery network或Content distribution network,簡稱CDN)中以因應大量存取。

    第九件事:勿超過API存取頻率限制

    為了防止太過巨量的存取,每一個LINE Messaging API帳號依據方案不同而有不同的API存取頻率限制,如下表所示。

    方案 呼叫頻率限制 收訊者數量頻率限制
    Developer Trial 1,000/min 20,000/min
    其他方案 10,000/min 200,000/min

    當存取LINE平台API的頻率超過限制時,API會回應「429 Too Many Requests」的錯誤訊息,此時只要降低存取的頻率到限制值以內即可恢復正常。一般用途的聊天機器人很少會大量存取LINE平台API,通常會發生超過存取頻率限制的狀況是聊天機器人利用LINE Messaging API推播廣告訊息給用戶;若要同時發送大量內容相同的訊息,我們建議開發者改用官方帳號/LINE@管理工具,速度與穩定度都會比較高。

    第十件事:善用LINE Bot SDK

    對於初學者而言,最快能建立一個LINE聊天機器人的方法應該就是套用LINE Bot SDK。LINE Bot SDK提供各種常見程式語言的函式庫,讓開發者很輕易便能開發LINE Messaging API的應用程式。這些SDK還包括範例程式,讓初學者能更快瞭解如何使用函式庫。以下是LINE Bot SDK所支援的程式語言列表。

  • Java
  • PHP
  • Go
  • Perl
  • Ruby
  • Python
  • Node.js
  • 如果在開發LINE聊天機器人時遇到一些問題,也可以在「Frequently asked questions about LINE bots」參考常見的問答,也許可以找到所需要的資訊喔!

    chatbot Messaging API guideline

    Augustin Wang 2017.08.01

    LINE台灣首席應用分析師,負責LINE平台產品的技術與應用研發。

    Add this entry to Hatena bookmark

    回到文章列表