Creating a Line BOT on Microsoft Azure
![](https://developers.line.me/wp-content/uploads/2016/04/bot_img001.png)
Pre-conditions
- Node.js with Express & Jade
- Microsoft Azure App Service
- Line BOT trial account
Node.js with Express & Jade
- Install Node.js with Express & Jade
- Create an Express project (Ref.: Express application generator)
$ express LineBOT
- Install dependencies
$ cd LineBOT $ npm install
- Run the app
$ DEBUG=LineBot:* npm start > LineBOT@0.0.0 start /Users/phchu/Documents/Nodejs/LineBOT > node ./bin/www
- Open the url
GET / 304 400.918 ms - - GET /stylesheets/style.css 304 3.950 ms - -
Microsoft Azure App Service
Advantages:- Free
- SSL(https)
- fixed IP address (it's important to configure Line BOT callback server's white list)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_DxpzXxmJ-OZzQKt-HhwGV37929avhZ8AQNMn5MznksR_Yvhq1o30phgnX0kFrFHAfT2qLJg4_NvAGhlew2vcOEusqdjnTDfR1lqFYeryUohC_qmYob4Sxk3G_Xp6Yo0-LiuA0QLEr5I/s640/Microsoft+Azure+App+Service-1.png)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVFaJl7iTqnDWpKUzC6TIV-A1qLKu_MK-0-GwWEWezJjmPYjv17qhUPaq-Pag2zviObP0MVEobyAwJx5Hw_lnu1gQFSDhuMJpNu9IpvZWDkuB_OVIAddmlhr6_I_kQ-Tviwn_6Zi4cnZQ/s640/Microsoft+Azure+App+Service-2.jpg)
Deploy the "LineBOT" project generated in previous step
- Install Azure CLI & login
$ azure login info: Executing command login |info: To sign in, use a web browser to open the page https://aka.ms/devicelogin. Enter the code ********* to authenticate. /info: Added subscription Enterprise info: Added subscription Azure in Open + info: login command OK
- Create the site by "azure site create --git {appname}"
$ azure site create --git phbot azure site create --git phbot info: Executing command site create + Getting sites + Getting locations help: Choose a location 1) South Central US 2) North Europe 3) West Europe 4) Southeast Asia 5) East Asia 6) West US 7) East US 8) Japan West 9) Japan East 10) East US 2 11) North Central US 12) Central US 13) Brazil South 14) Canada Central 15) Canada East : 5 info: Creating a new web site at phbot.azurewebsites.net \info: Created website at phbot.azurewebsites.net + info: Executing `git init` info: Creating default iisnode.yml file info: Initializing remote Azure repository + Updating site information info: Remote azure repository initialized + Getting site information + Getting user information help: Please provide the username for Git deployment Publishing username: phchu info: Executing `git remote add azure https://phchu@phbot.scm.azurewebsites.net/phbot.git` info: A new remote, 'azure', has been added to your local git repository info: Use git locally to make changes to your site, commit, and then use 'git push azure master' to deploy to Azure info: site create command OK
- Deploy app to Azure
$ git add . $ git commit -m "initial commit" [master (root-commit) e2a8aba] initial commit 12 files changed, 314 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 app.js create mode 100755 bin/www create mode 100644 iisnode.yml create mode 100644 npm-debug.log create mode 100644 package.json create mode 100644 public/stylesheets/style.css create mode 100644 routes/index.js create mode 100644 routes/users.js create mode 100644 views/error.jade create mode 100644 views/index.jade create mode 100644 views/layout.jade $ git push azure master
- Finally, launch the Azure app in the browser:
Tip: Use "azure site log tail" to see the console log
$ azure site log tail info: Executing command site log tail + Getting site information Welcome, you are now connected to log-streaming service.
Line BOT trial account
We have to get the following attributes from the trial account:
- Channel ID
- Channel Secret (Click "Show" button to see it)
- MID
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrwECpwqgzj9AKwOa3_x1YxplS2z5hNmb7rj_DqNRiQIrXTi_G98EfXir8GGz5y9Q3sgpmXIOP6eSf9fRbXDUi7MNzSEhTVV-uugOSJNXRMIWAyRINIJKvx4bsSQutSQ4fZlQ7KrFp8cs/s400/Line_BOT_Trail_Account.jpg)
Configure the Line BOT account attributes in project
Creating a file named "config.js" as below:module.exports = { 'LINE':{ CHANNEL_ID: '1234567890', CHANNEL_SERECT: '1ad5135ufygthrjekadf107d2', MID: '0s98d7f65g4h3jki2u3y4t5re678w9', } };
Setup the "Callback URL" in channel
Callback URL format: http://[app_name].azurewebsites.net:433/[router]Ref.: Getting started with BOT API Trial-Registering a callback URL
https://phbot.azurewebsites.net:443/callback
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOodqcpZR0_T0OlS6HUXIbdej86rFEK1wBhk-5g_zAY6GBC5OoGucW5wTrIjKEhiAJMVschOIg-i9lC8EVQ0x_OL7HWN9EyuZ5cY0hfloIhQPRd9w1qqxaN7sPRNCvNBxEGKfBAZTrkMA/s400/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2016-06-19+%25E4%25B8%258B%25E5%258D%258812.05.11.jpg)
Create the callback router in the project
- Create "callback.js" in folder routes
var express = require('express'); var router = express.Router(); /* GET line bot callback. */ router.post('/', function(req, res, next) { res.send('respond with a resource'); }); module.exports = router;
- Configure the routing in app.js
var callback = require('./routes/callback'); app.use('/callback', callback);
- Verify the callback URL
Click the "VERIFY" button, and it will show "Success." message.
$ azure site log tail info: Executing command site log tail + Getting site information Welcome, you are now connected to log-streaming service. POST /callback 200 6.439 ms - 23
Line BOT API
Add fixed propreties in config.js
module.exports = { 'LINE':{ API: 'https://trialbot-api.line.me/v1/', CHANNEL_ID: '1234567890', CHANNEL_SERECT: '1ad5135ufygthrjekadf107d2', MID: '0s98d7f65g4h3jki2u3y4t5re678w9', TEXT: 1, IMAGE: 2, } };
Receive message
- Add BOT as a friend by scanning the QR-code above Callback URL
- Add console.log in callback.js to show message content then commit it
/* GET line bot callback. */ router.post('/', function(req, res, next) { console.log('callback: ', req.body); var result = req.body.result; for(var i=0; i < result.length; i++){ var data = result[i].content; console.log('message content: ', data); } });
- Say "Hi, BOT" to the online Line BOT
Console:
callback: { result: [ { content: [Object], createdTime: 1466386987962, eventType: '138311609000106303', from: 'u09y8t76r5e4ws8d7f6g5h4jdfghjkxcvbnmkl', fromChannel: 1341301815, id: 'WB1520-3548181394', to: [Object], toChannel: 1234567890 } ] } message content: { toType: 1, createdTime: 1466386987943, from: 'u09y8t76r5e4ws8d7f6g5h4jdfghjkxcvbnmkl', location: null, id: '4488676771230', to: [ 'sdfghjk8f7gh6j5k4l30lk98j7h6g5f4d3s' ], text: 'Hi, BOT', contentMetadata: { AT_RECV_MODE: '2', SKIP_BADGE_COUNT: 'true' }, deliveredTime: 0, contentType: 1, seq: null }
Send text message
- Install module dependency: request
npm install request --save
- Add a new function sendMessage to reply(repeat) sender's message
function sendMessage(sender, content, type) { console.log('Send message: ', content); var query_fields = 'events'; var data; switch (type) { case config.LINE.TEXT: data = { to: [sender], //Array of target user. Max count: 150. toChannel: 1383378250, //Fixed value eventType: '138311608800106203',//Fixed value content: { contentType: type, toType: 1, text: content } }; break; default: break; } console.log('Send data: ', data); request({ url: config.LINE.API.concat(query_fields), headers: { 'Content-Type': 'application/json; charset=UTF-8', 'X-Line-ChannelID': config.LINE.CHANNEL_ID, 'X-Line-ChannelSecret': config.LINE.CHANNEL_SERECT, 'X-Line-Trusted-User-With-ACL': config.LINE.MID }, method: 'POST', body: JSON.stringify(data) }, function (error, response, body) { if (error) { console.log('Error sending message: ', error); } else if (response.body.error) { console.log('Error: ', response.body.error); } console.log('Send message response: ', body); }); }
- Reply sender's message by repeating it
/* GET line bot callback. */ router.post('/', function(req, res, next) { console.log('callback: ', req.body); var result = req.body.result; for(var i = 0; i < result.length; i++){ var data = result[i].content; console.log('message content: ', data); sendMessage(data.from, data.text, config.LINE.TEXT); } });
- Commit and Try it
Ater replying message successfully, the BOT will receive a response with messageId and timestamp.
Console
Send message response: { "failed": [], "messageId": "1466392481962", "timestamp": 1466392481962, "version": 1 }
If you received the following response, add the denied IP address in whitelist
Send message response: { "statusCode": "427", "statusMessage": "Your ip address [213.73.167.123] is not allowed to access this API. Please add your IP to the IP whitelist in the developer center." }
Get user profile
- Add a new function queryProfile to query sender's name
function queryProfile(sender, callback) { var query_fields = 'profiles?mids='; request({ url: config.LINE.API.concat(query_fields, sender), headers: { 'Content-Type': 'application/json; charset=UTF-8', 'X-Line-ChannelID': config.LINE.CHANNEL_ID, 'X-Line-ChannelSecret': config.LINE.CHANNEL_SERECT, 'X-Line-Trusted-User-With-ACL': config.LINE.MID }, method: 'GET' }, function (error, response, body) { if (error) { console.log('Error sending message: ', error); } else if (response.body.error) { console.log('Error: ', response.body.error); } var jsonResult = JSON.parse(body); console.log('Profile response: ', jsonResult); for (var i = 0; i < jsonResult.count; i++) { var userName = jsonResult.contacts[i].displayName; console.log('User name: ', userName); callback(userName); } }); }
- Reply sender's message by saying "Hi, [user_name]"
/* GET line bot callback. */ router.post('/', function(req, res, next) { console.log('callback: ', req.body); var result = req.body.result; for(var i = 0; i < result.length; i++){ var data = result[i].content; console.log('message content: ', data); queryProfile(data.from, function(user) { var reply_msg = 'Hi, '.concat(user); sendMessage(data.from, reply_msg, config.LINE.TEXT); }); } });
- Commit and Try it
Console:
Profile response: { contacts: [ { displayName: 'phchu', mid: 'sdfghjk8f7gh6j5k4l30lk98j7h6g5f4d3s', pictureUrl: '', statusMessage: '' } ], count: 1, display: 1, pagingRequest: { start: 1, display: 1, sortBy: 'MID' }, start: 1, total: 1 } User name: phchu Send message: Hi, phchu Send data: { to: [ 'sdfghjk8f7gh6j5k4l30lk98j7h6g5f4d3s' ], toChannel: 1383378250, eventType: '138311608800106203', content: { contentType: 1, toType: 1, text: 'Hi, phchu' } } Send message response: {"failed":[],"messageId":"1466394625241","timestamp":1466394625241,"version":1}
Send image message
- Reply sender's message by an image
If sender's message contains string "Hi,", replying message by saying "Hi, [user_name]". Otherwise, replying the image sticker as below.
- Add a new image message type in sendMessage function
case config.LINE.IMAGE: data = { to: [sender], toChannel: 1383378250, eventType: '138311608800106203', content: { contentType: type, toType: 1, originalContentUrl: content, previewImageUrl: content } }; break;
- Commit and Try it
Console:
Send message: https://sdl-stickershop.line.naver.jp/products/0/0/4/1331/android/stickers/23770.png Send data: { to: [ 'sdfghjk8f7gh6j5k4l30lk98j7h6g5f4d3s' ], toChannel: 1383378250, eventType: '138311608800106203', content: { contentType: 2, toType: 1, originalContentUrl: 'https://sdl-stickershop.line.naver.jp/products/0/0/4/1331/android/stickers/23770.png', previewImageUrl: 'https://sdl-stickershop.line.naver.jp/products/0/0/4/1331/android/stickers/23770.png' } } Send message response: {"failed":[],"messageId":"1466396249482","timestamp":1466396249482,"version":1}
Final Result
View on GitHub
0 意見:
張貼留言