Geekになりたいママエンジニアのブログ

子育てを楽しみつつ空き時間に自己啓発をしているログです。投稿する内容はすべて個人の意見であり、所属する組織とは関係がありません。

LINEのボットを作ってみました(Azure + node.js)

情報系の勉強をはじめたてのまだ学生だった頃、会話の相手をしてくれるようなロボットを作りたいと夢見ていました。最近チャットボットのようなサービスが流行りだし、そんな昔の夢を思い出しました😊今回は、今更感はありますが、LINEのチャットボットを作ることに挑戦してみようと思います。

LINEのドキュメント「ボットを作成する」
https://developers.line.me/ja/docs/messaging-api/building-bot/

LINEのボット用アカウントを作成する手順などは↑のページに書いてあるので割愛し、以下Webhookペイロードを受け取るためのサーバーを作成する手順を記録しておきます。

Webhookペイロードとは

友達申請が届いた場合やユーザからメッセージを受信した場合、LINEサーバーから登録したURLに通知が届きます。具体的には、”LINE developers”のコンソールにて、チャネル基本設定→メッセージ送受信設定→Webhook送信の設定を「利用する」にすると、登録してあるWebhook URL(チャネル基本設定→メッセージ送受信設定→Webhook URL)にPOSTリクエストが届きます。サーバー上にて届いたPOSTリクエストを解析し、友達申請に反応する、メッセージに返信するなどの処理を行うことができます。

node.jsにてページを作ってみる。

node.js on Azureでページを作成してみました。無料試用版なので今のところ無料です。クイック スタート:Node.js Web アプリを作成する - Azure App Service | Microsoft Learnに沿ってWebページを作成しましたが、とても簡単にHello World!ページを作成することができました!ちなみに、node.jsもAzureも今回初めて触る初心者です。

上記のページよりダウンロードしたサンプルコードには、index.jsというJavaScriptファイルが含まれています。このJavaScriptファイルがHTTPリクエストの解析やWebページの出力などを行っているようです。(同フォルダにあるweb.configにて、index.jsを使う旨が定義されています。)

index.jsの中身を見てみると、http.createServer関数の第一引数に指定した関数の中で、requestを処理してresponseを生成しています。

var server = http.createServer(function(request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.end("Hello World!");
});

今回は、LINEサーバーから私が作成するページにPOSTリクエストが届いた際に処理を行うようにしないといけません。/webhook/というURLにPOSTリクエストが届いた場合に検出できるようにしたいと思います。

var server = http.createServer(function (request, response) {
    if ((request.url === '/webhook/') && (request.method === 'POST')) {
        // /webhook/ URLに届いたPOSTリクエストのみを処理します。
        response.writeHead(200, { "Content-Type": "text/plain" });
        response.end("POST request is detected");
    }
});

”LINE developers”のコンソールの チャネル基本設定→メッセージ送受信設定→Webhook URL にて接続確認ができました!

ちなみに、GETリクエストを送るとエラーになります。

Expressフレームワークを試してみる。

Expressとは、node.js上で動くwebフレームワークです。

npm install express --save

とコマンド入力するだけで簡単に導入することができます。

Expressを使うと、よりコードが簡潔になりました。URLが増えるようであれば、Expressを利用したほうがよさそうです。

const express = require('express');
const app = express();

var port = process.env.PORT || 1337;
app.listen(port);

app.post('/webhook/', function (request, response) {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("POST request is detected");
})

署名を検証する

次に届いたリクエストを解析・処理する部分を実装します。まずは、Webhook URLに届いたリクエストが本当にLINEサーバーから送られたものだということを確認します。この工程を省いてしまうと、たとえば悪意のあるユーザがWebhook URLに適当なリクエストを送ることで私のサーバーからLINE messageを送るようなことができるようになってしまいます。

const request = require('request');
const express = require('express');
const bodyParser = require('body-parser'); // 署名情報が格納されているrequest.bodyの中身を読むために必要

const app = express();
app.use(bodyParser.json());   

const port = process.env.PORT || 1337;
app.listen(port);

app.post('/webhook/', function (request, response) {
    const crypto = require('crypto');
    const signature = crypto
        .createHmac('SHA256', <channelSecret>)
        .update(JSON.stringify(request.body)).digest('base64');
    if (signature === request.headers['x-line-signature']) {
        // 署名OK!
    }
    else {
        // 不正な署名
        console.log("Signature error.");
        response.writeHead(500, { "Content-Type": "text/plain" });
    }
});

参考:https://developers.line.me/ja/reference/messaging-api/#signature-validation

メッセージに返信する

とりあえず、メッセージが届いた場合には、適当に返信するようにしました。replyMessage APIを呼び出すと、https://api.line.me/v2/bot/message/replyにPOSTメッセージが送られます。

const line = require('@line/bot-sdk');
const client = new line.Client({ channelAccessToken: '***'});

for (var i = 0; i < request.body.events.length; i++) {
    var event = request.body.events[i];
    if (event.type === 'message') {
        response.json(client.replyMessage(event.replyToken, {
            type: 'text',
            text: 'メッセージありがとうございます😊'
        }));
    }
 }

参考:
https://developers.line.me/ja/reference/messaging-api/#send-reply-message

行き詰まった点

Azureサーバーのログをどこから見ることができるのか分からずすこしはまりました。https://{チャネル名}.scm.azurewebsites.net/api/logstreamにて見ることができましたが、あまり使い勝手がよくないのでもっと良い方法があるかもしれません。

概要

下手な絵で概要を説明してみるシリーズです。

シーケンス図