- 2024/5/11 ngrok仕様変更に伴うlinegrok v2へのバージョンアップにより内容更新しました
ngrokって便利ですよね
LINE Bot開発ではローカル実行したBotサーバーへパブリックにアクセスする手段としてngrokがとても便利ですよね😊
ただngrokって毎回ランダムなサブドメインのURLが発行されるので、起動のたびにLINE DevelopersコンソールからWebhook URLを変更しなきゃいけないのがなかなかつらいとこだと思います。
さらに、先日LINE DCハッカソンに参加した際に久しぶりにngrok使ったのですが、前は8時間ぐらいURLが有効だったはずが2時間で無効になるようになっていました。
ただでさえ大忙しなハッカソン中に何度もWebhook URLを更新しなければならず、つらみの極みでした😢
このつらみを解決するべく「linegrok」というライブラリを作ってみました。
linegrok
miso-develop/linegrok (GitHub)
どんなものかというとngrokの起動およびURL取得と、LINE DevelopersコンソールへのWebhook URL更新を同時に行う関数を提供するライブラリです。
さらにngrokを認証していない場合は2時間でURLが無効となりますが、1時間半おきにngrok URLの再発行とWebhook URLの更新を自動で行い続けてくれます。
→ ngrokの仕様変更によりngrok未認証では使えなくなったようなので上記取り消し線の機能は無効化しました
Botのコードでlinegrok
関数を実行しておくだけで、Webhook URLに関することをまったく意識せずBot開発を行うことができます🤩
使い方
インストール
$ npm install linegrok
linegrok
関数
LINE BotのClientと、portを引数にわたして実行します。
あとは自動的にngrokプロセスが立ち上がり、発行されたngrok URLをClientに紐づくチャネルのWebhook URLに設定します。
const { linegrok } = require("linegrok")
const channelAccessToken = process.env.CHANNEL_ACCESS_TOKEN
const port = process.env.PORT
// LINE BotのchannelAccessTokenとportを引数にわたして実行
linegrok({ channelAccessToken, port })
...
オプション
channelAccessToken
、port
が必須となります。
それ以外にもいくつか任意オプションがあります。
オプション | 必須 | 既定値 | 内容 |
---|---|---|---|
channelAccessToken | ✔ | - | LINE BotのChannel Access Tokenを指定します。 このChannel Access Tokenに紐づくチャネルのWebhook URLが自動更新されます。 |
port | ✔ | - | Botサーバーのポート番号を指定します。 |
path | "/" | Webhook URLのpathを指定します。 | |
authtoken | undefined | ngrokのAuth Tokenを指定します。 | |
region | "ja" | ngrokのリージョンを指定します。 |
使用例
例としてオウム返しBotのコードは以下のようになります。
環境変数にてCHANNEL_ACCESS_TOKEN
、CHANNEL_SECRET
を設定して実行してみてください。
const express = require("express")
const { messagingApi, middleware } = require("@line/bot-sdk")
const { linegrok } = require("linegrok")
const channelAccessToken = process.env.CHANNEL_ACCESS_TOKEN
const channelSecret = process.env.CHANNEL_SECRET
const port = process.env.PORT
linegrok({ channelAccessToken, port })
const client = new messagingApi.MessagingApiClient({ channelAccessToken })
const app = express()
app.post("/", middleware({ channelSecret }), (req, res) => {
handleEvents(req.body.events)
res.send({ status: 200 })
})
app.listen(port, () => console.log(`Start server!`))
const handleEvents = events => {
events.forEach(event => {
switch (event.type) {
case "message": client.replyMessage({
replyToken: event.replyToken,
messages: [{
type: "text",
text: event.message.text,
}]
}); break
}
})
}