Knowledge Stones

フリーランスエンジニアの技術ブログです。

LINE Messaging APIを使用してチャットボットを作ってみる【②Lambdaで実装編】

f:id:polar_bear_tech:20190911232546p:plain

Lambdaで作ってみよう

AWS Lambdaはサーバーレスのスクリプトなので、サーバーを立ち上げる手間なく動作の確認ができるので、手始めにはオススメです。

流れは大体こんな感じです。

  1. AWS Lambdaで実装
  2. AWS API Gatewayの設定
  3. LINE BotアカウントにWebhookを設定

 

 

AWS Lambdaで実装

 ランタイムはNode.js 10.xを使用しています。 

@line/bot-sdkを使用して受信メッセージを読み込み、返信までを行なっています。

'use strict';

const line = require('@line/bot-sdk');
const crypto = require('crypto');

// 環境変数の読み込み const channelSecret = process.env.CHANNELSECRET; const channelAccessToken = process.env.ACCESSTOKEN;
// LINE Clientオブジェクトの作成 const client = new line.Client({channelAccessToken: channelAccessToken}); exports.handler = function (event, context) { const body = JSON.parse(event.body); console.log(event); // (1)HMACを用いて正規のLINEサーバからのリクエストであることを確認 const signature = crypto.createHmac('SHA256', channelSecret).update(event.body).digest('base64'); const xLineSignature = (event.headers || {})['X-Line-Signature']; let verified = false; if (signature === xLineSignature) { verified = true; } if(!verified){ // 正規のLINEサーバからのリクエストでない場合 console.log("Signature verify error."); } else{ // 正規のLINEサーバの場合 console.log("Signature verify succeed."); let replyToken = body.events[0].replyToken; // リクエストの内容を確認 if(replyToken === '00000000000000000000000000000000'){ // 接続確認の場合 console.log("Connection check."); let response = { statusCode: 200, headers: { "X-Line-Status" : "OK" }, body: '{"result":"connect check"}' } context.succeed(response); } else{ // 通常メッセージの場合 console.log("Message received."); let message = body.events[0].message; // (2)メッセージのTypeから返答を設定する console.log("Message type :" + JSON.stringify(message.type)); let reply_text = null; if(JSON.stringify(message.type) == "\"text\""){ // テキストの場合 let text = body.events[0].message.text; switch (text) { case "グー": reply_text = "パー" break; case "チョキ": reply_text = "グー" break; case "パー": reply_text = "チョキ" break; default: reply_text = "興味ないね" break; } } else{ // テキスト以外の場合 reply_text = "..."; } // 返信メッセージの作成 let res_message = { "type": "text", "text": reply_text }; // (3)メッセージの返信 client.replyMessage(replyToken, res_message) .then((res) => { let response = { statusCode: 200, headers: { "X-Line-Status" : "OK"}, body: '{"result":"reply completed"}' }; context.succeed(response); }).catch((err) => console.log(err)); } } }; 

何をやっているのかは、LINEのドキュメントを確認すれば丁寧に書いてありますが、一部抜粋して解説します。

 

(1) HMACを用いて正規のLINEサーバからのリクエストであることを確認

LINE Botアカウントに”Channel Secret”という文字列が設定されています。

下記の処理は、これを使ってメッセージ全体をハッシュ化し、BASE64エンコードした文字列を作成し、リクエストヘッダーに含まれる”X-Line-Signature”というパラメータと値を比較しています。

const signature = crypto.createHmac('SHA256', channelSecret).update(event.body).digest('base64');
const xLineSignature = (event.headers || {})['X-Line-Signature'];
let verified = false;
if (signature === xLineSignature) {
  verified = true; 
}

LINEサーバーは、”X-Line-Signature”に同じようにして生成した文字列を入れて送ってくるわけです。

これは"Channel Secret"を知らない他人にはできないため、この照合によって、正規のLINEサーバーから送られてきたかどうかを確認できるわけです。

※注意:Channel Secretをプログラムにベタ書きしてGithubでばらまいてしまっては話は別です。他人に知られないように。

 

(2) メッセージのTypeから返答を設定する

正規のLINEサーバからのリクエストだとわかったら、メッセージの中身を確認します。

let message = body.events[0].message;
if(JSON.stringify(message.type) == "\"text\""){
  // テキストメッセージの場合
}else{ // それ以外の場合
}

本来は、メッセージよりも前に"event"という要素を確認すべきですが、割愛します。

"message"要素の"type"には、"text","sticker","image"...など、どんなメッセージが来たかが書いてあります。

それを元に分岐を作って、返答を作っていくことになります。

 

(3) メッセージの返信

メッセージを返信するには、受信したメッセージに含まれる"replyToken"を使います。

合わせてメッセージを詰めて返信し、通信のステータスが"200"なら返信成功、失敗したらログを残す、といった内容です。

client.replyMessage(replyToken, res_message)
.then((res) => {
let response = {
statusCode: 200,
headers: { "X-Line-Status" : "OK"},
body: '{"result":"reply completed"}'
};
context.succeed(response);
}).catch((err) => console.log(err));

まずは全てコピペで良いと思います。

 

あと、プログラムの上部で環境変数を読み込んでいますが、Lambdaには環境変数を設定することができます。

下記のようにLINE Botアカウントの画面から、該当項目を確認して値を設定しておきましょう。

チャンネルアクセストークンはWebhook送信を「利用する」に設定して、「再発行」ボタンを押せば発行できます。

f:id:polar_bear_tech:20190911222916p:plain

 

AWS API Gatewayの設定

次にAPI Gatewayを設定します。

まずは「+APIの作成」ボタンからこんな感じで作成します。

f:id:polar_bear_tech:20190911223423p:plain

 

次に「アクション」からPOSTメソッドを作成します。

  • 統合タイプ:Lambda関数
  • Lambdaプロキシ統合の使用:✔︎
  • Lambda関数:先ほど作成した関数名
  • デフォルトタイムアウトの使用:一応3秒くらい待つようにしました

f:id:polar_bear_tech:20190911224726p:plain



 

最後に、「アクション」から「APIのデプロイ」を行います。

ステージ名はこだわらなければ適当で構いません。

f:id:polar_bear_tech:20190911224312p:plain

 

そうすると、URLが発行されます。

f:id:polar_bear_tech:20190911224751p:plain

 

LINE BotアカウントにWebhookを設定

発行されたURLをLINE Botのアカウントにある「WebhookURL」へ設定します。

f:id:polar_bear_tech:20190911224947p:plain

で、「接続確認」ボタンを押して、成功しましたと出ればOK!

 

あとは、Webhookでアプリケーションで応答をする場合、デフォルトの応答設定が邪魔になるので、下記のように「挨拶メッセージ」「応答メッセージ」はオフにしてWebhookをオンにしましょう。

f:id:polar_bear_tech:20190911225113p:plain

 

あとはLINE BotをQRコードで友達登録して、メッセージを送ってみると・・・

f:id:polar_bear_tech:20190911225428p:plain

応答が返ってきました!くだらないですね!

 

終わりに

ここまでできれば、あとはプログラムの中身を工夫するだけで、ちょっとしたボットは作れちゃいます!

 

AWS API Gatewayは無料利用枠があり、月間のメッセージ数 100 万件 (送信または受信) および接続時間 750,000 分以内は無料です。

Lambdaもリージョンによりますが、東京は1 か月に 1,000,000 件のリクエストおよび 400,000 GB-秒のコンピューティング時間は無料のようなので、ちょっと試しに作る分には無料で実現できそうですね。

 

小一時間あればできるので、ぜひやってみてください!