LINE Messaging APIを使用して、LINEボットを開発していました。
そこでメッセージイベントに加えてポストバックイベントのイベント処理を実装する必要がありました。
とりあえずメッセージイベント発生時はLINEに”This is a test”を送信し、ポストバックイベント発生時はポストバックの内容(postback.data
)をログに出力するよう実装しました。
以下、Lambda(Node.js)のソースコードです。
'use strict';
const line = require('@line/bot-sdk');
const crypto = require('crypto');
const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });
function executeLambdaResponse(context) {
let lambdaResponse = {
statusCode: 200,
headers: { "x-line-status": "OK" },
body: '{"result":"connect check"}'
};
context.succeed(lambdaResponse);
}
exports.handler = (event, context) => {
let signature = crypto.createHmac('sha256', process.env.CHANNELSECRET).update(event.body).digest('base64');
let checkHeader = (event.headers || {})['x-line-signature'];
let body = JSON.parse(event.body);
let text = body.events[0].message.text
let postback = body.events[0].postback.data
if (signature === checkHeader) {
if (body.events[0].replyToken === '00000000000000000000000000000000') { //接続確認エラー回避
executeLambdaResponse(context)
} else if (text == "test") {
const message = {
'type': 'text',
'text': 'This is a test'
};
client.replyMessage(body.events[0].replyToken, message)
.then(() => {
executeLambdaResponse(context)
}).catch((err) => console.log(err));
} else if (postback == "test2") {
console.log(postback)
}
} else {
console.log('署名認証エラー');
}
console.log(`EVENT: ${JSON.stringify(event)}`);
};
そして、実際にLINEからポストバックイベントを発生させるとLambdaで以下のエラーが発生しました。
{
"errorType": "TypeError",
"errorMessage": "Cannot read property 'text' of undefined",
"stack": [
"TypeError: Cannot read property 'text' of undefined",
" at Runtime.exports.handler (/var/task/index.js:128:37)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]
}
textが定義されていないとのことです。以下の記載に問題があることがわかりました。
let text = body.events[0].message.text
let postback = body.events[0].postback.data
ポストバックイベント発生時に生成されるオブジェクトにはmessageプロパティ
が存在しません。そのためbody.events[0].message.text
が参照不可となりtext undefined
のエラーになったみたいです。
イベントの種類によってLINE側で生成するオブジェクトの構成が変わるのでそれを考慮して実装する必要がありました。
下のように存在しないプロパティの参照を防ぐよう修正したら、エラーを解決できました。
let text = ""
let postback = ""
if (body.events[0].type == "message") {
text = body.events[0].message.text
} else if (body.events[0].type == "postback") {
postback = body.events[0].postback.data
}
メッセージイベント発生時にはbody.events[0].message.text
プロパティにアクセスし、ポストバックイベント発生時にはbody.events[0].postback.data
プロパティにアクセスするようにしています。
修正後のソースコード(全体)
'use strict';
const line = require('@line/bot-sdk');
const crypto = require('crypto');
const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });
function executeLambdaResponse(context) {
let lambdaResponse = {
statusCode: 200,
headers: { "x-line-status": "OK" },
body: '{"result":"connect check"}'
};
context.succeed(lambdaResponse);
}
exports.handler = (event, context) => {
let signature = crypto.createHmac('sha256', process.env.CHANNELSECRET).update(event.body).digest('base64');
let checkHeader = (event.headers || {})['x-line-signature'];
let body = JSON.parse(event.body);
let text = ""
let postback = ""
if (body.events[0].type == "message") {
text = body.events[0].message.text
} else if (body.events[0].type == "postback") {
postback = body.events[0].postback.data
}
if (signature === checkHeader) {
if (body.events[0].replyToken === '00000000000000000000000000000000') { //接続確認エラー回避
executeLambdaResponse(context)
} else if (text == "test") {
const message = {
'type': 'text',
'text': 'This is a test'
};
client.replyMessage(body.events[0].replyToken, message)
.then(() => {
executeLambdaResponse(context)
}).catch((err) => console.log(err));
} else if (postback == "test2") {
console.log(postback)
}
} else {
console.log('署名認証エラー');
}
console.log(`EVENT: ${JSON.stringify(event)}`);
};
あとがき
複数のtype
のイベントオブジェクトを扱う予定がある人は注意ですね。それぞれのtype
が持つプロパティの情報は以下の公式ドキュメントから確認できます。
コメント