티스토리 뷰

이제 Nodejs를 이용해서 AWS에 올라갈 서버를 만들어 보도록 하겠습니다. 비지니스 로직 구현에 참고할 문서는 Messaging API(https://devdocs.line.me/en/)를 참고하였습니다. 여기서는 서버 설정과 간단히 응답하는 코드에 대해서만 설명하도록 하겠습니다.


아래 내용은 express module에 대해서 알고 있다는 전제하에 진행하도록 하겠습니다.




1. SSL 설정하기


우리가 만든 서버에서 https protocol을 사용하기 위해서는 서버에 SSL 설정을 해주어야합니다. 인증 설정을 하기 위해서는 .ca-bundle 파일 / .key 파일 / .crt파일이 필요합니다. 위 파일들은 인증서를 발급할때 인증기관을 통하여 얻을 수 있습니다. (comodo 인증기관의 경우 인증이 완료되면 메일 첨부파일을 통해 다운받을 수 있습니다)


 https 프로토콜을 사용하기 위해 https module을 임포트 합니다. 인증서를 등록하기 위해 앞에서 언급한 파일들을 file system module를 이용해서 불러와 객체로 만들어줍니다. 이렇게 만든 https_options객체를 서버를 생성할 때, 첫번째 옵션에 파라미터로 넘겨줍니다. 마지막으로 SSL 프로토콜인 443으로 서버를 띄어주면 SSL 설정작업은 끝입니다.

const https = require('https');
const express = require('express');
const fs = require('fs');

const config = require('./config');

var app = express();

// set SSL
var https_options = {
ca: fs.readFileSync(config.SSL.CA_PATH, 'utf8'),
key: fs.readFileSync(config.SSL.KEY_PATH, 'utf8'),
cert: fs.readFileSync(config.SSL.CERT_PATH, 'utf8')
};

https.createServer(https_options, app).listen(443, function(){
console.log("Momo Server is Running");
});




2. Webhook Object Parsing 하기


유저가 메세지를 전송했을 때 hook할 로직을 만들어 보도록 하겠습니다.

express module로 생성한 app 객체에 '/hook' url로 post방식으로 들어왔을때 정보를 파싱해서 어떤 동작을 할지 로직을 구현해주면 되겠습니다.


Messaging API를 이용해서 서버로 넘어올때 JSON 타입으로 Webhook Object가 넘어옵니다. 여기서 이 오브젝트를 파싱해서 어떤 메세지가 어디서 왔는지 알 수 있습니다.



Webhook Object 자세한 구조는 다음 사이트에서 확인하실 수 있습니다.

https://devdocs.line.me/en/#webhook-event-object




 express module에서 webhook URL정보를 추출하기 위해 bodyParser module을 이용하도록 하겠습니다. bodyParser module을 불러온 후에 express 모듈의 use메소드에 bodyParser.json()을 등록해 줍니다.


 다음으로 '/hook' url에 post로 요청이 왔을때 로직을 구현해 주도록 하겠습니다. 아래 코드는 object정보를 읽어와서 출력해주는 코드입니다.  이 url은 앞에서 한번 언급한 bot developer site에 callback으로 등록하여 사용할 url입니다.

const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/hook', function (request, response) {

var eventObj = request.body.events[0];
var source = eventObj.source;
var message = eventObj.message;

// request log
console.log('======================', new Date() ,'======================');
console.log('[request]', request.body);
console.log('[request source] ', eventObj.source);
console.log('[request message]', eventObj.message);

response.sendStatus(200);
});



 이제 message 변수에 담겨있는 string을 분석하여, 특정 단어가 검출되었을때나 Webhook URL이 호출되었을 때 reply API를 이용하여 적절한 메세지를 보내주면 됩니다.


 nodejs에서 request를 보내기 위해서, 이 포스트에서는 request module을 사용하였습니다.

응답을 보낼 때 필요한 정보가 두가지가 있는데 첫번째로 Reply Token과 ChannelAccess Token입니다. Reply Token은 Webhook Object를 통해서 얻을 수 있고, Channel Access Token은 Bot Developer 페이지에서 발급받을 수 있습니다.  


 아래 함수는 Channel Access Token과 Reply Token, Messages String을 파라미터로 넘겨주어 reply API를 호출하는 함수 입니다.

const requestSender = require('request');

module.exports.send = function (channelAccessToken, replyToken, messages) {
var headers = {
'Content-type' : 'application/json',
'Authorization' : 'Bearer ' + channelAccessToken
};

var options = {
url: 'https://api.line.me/v2/bot/message/reply',
method: 'POST',
headers: headers,
json: {
replyToken : replyToken,
messages : messages
}
};

requestSender(options, function (error, response, body) {
console.log('response', response.statusCode);
if (!error && response.statusCode == 200) {
console.log(body)
}
else{
console.log('requestSender', error);
}
})

};




아래 코드는 현재 Momo Bot에서 사용되고 있는 풀버전이니 개발하실때 참고하시길 바랍니다.

const https = require('https');
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');

const config = require('./config');
const reply = require('./reply');
const actionBasic = require('./action/basic');
const actionHelp = require('./action/help');
const actionEnjoy = require('./action/enjoy');

var app = express();

// set SSL
var https_options = {
ca: fs.readFileSync(config.SSL.CA_PATH, 'utf8'),
key: fs.readFileSync(config.SSL.KEY_PATH, 'utf8'),
cert: fs.readFileSync(config.SSL.CERT_PATH, 'utf8')
};

app.use(bodyParser.json());

app.get('/hook', function (reqeust, response) {
response.writeHead(200, {'Content-Type' : 'text/html'});
response.end('<h1>Momo - phg2491@naver.com<h1>');
});

app.post('/hook', function (request, response) {

var eventObj = request.body.events[0];
var source = eventObj.source;
var message = eventObj.message;

// request log
console.log('======================', new Date() ,'======================');
console.log('[request]', request.body);
console.log('[request source] ', eventObj.source);
console.log('[request message]', eventObj.message);

if(message.type = "text" && message.text.indexOf("@momo") != -1){
reply.send(config.CHANNEL_ACCESS_TOKEN, eventObj.replyToken, actionBasic.getBasicExpress());
}
else if(message.type = "text" && /^@.+/g.test(message.text)){
var cmd = message.text.split('@')[1];
console.log('[command]', cmd);

if(typeof cmd !== "undefined" && cmd != ""){
if(cmd == "h" || cmd == "help"){
reply.send(config.CHANNEL_ACCESS_TOKEN, eventObj.replyToken, actionHelp.getHelpExpress());
}
else if(/^r\[.+\]/g.test(cmd)){
reply.send(config.CHANNEL_ACCESS_TOKEN, eventObj.replyToken, actionEnjoy.getRandomExpress(cmd));
}
else if(cmd == "food" || cmd == "밥집"){
reply.send(config.CHANNEL_ACCESS_TOKEN, eventObj.replyToken, actionEnjoy.getFoodExpress());
}
else if(cmd == "contact" || cmd == "ct"){
reply.send(config.CHANNEL_ACCESS_TOKEN, eventObj.replyToken, actionHelp.getContactExpress());
}
}
}
response.sendStatus(200);
});

https.createServer(https_options, app).listen(443, function(){
console.log("Momo Server is Running");
});


이상으로 라인 봇 개발에 대한 포스팅을 마치도록 하겠습니다. 

위에 설명한 코드들은 Momo Repository(https://github.com/haegul/Momo)에서 확인하실 수 있습니다.


질문이나 보완점에 대해서는 덧글로 달아주시면 감사하겠습니다 :)



댓글
  • 프로필사진 코코몽 안녕하세요?
    설치할때, 일반 php 호스팅에서는 불가능한가요? node.js 호스팅을 이용해야 하나요?
    https 보안서버 설치되어 있는 상태입니다.
    2017.04.05 06:54 신고
  • 프로필사진 Dev-Momo 답장이 늦었습니다. 일반 php에서도 가능하지만 현재 소스코드로는 nodejs 코드이므로 포팅하셔야합니다. 2017.04.15 17:39 신고
  • 프로필사진 시리얼 안녕하세요.

    본 코드를 통해서 동작 방법을 알고 싶어서 github에서 다운로드 받았는데요.

    momo.js를 실행하기만 하면 되는건가요?

    API와 그런것들은 다 설정했는데, 키를 어디다 넣는것인지 잘 모르겠네요
    2017.06.14 01:43 신고
  • 프로필사진 Dev-Momo 안녕하세요. 1편부터 읽으셨으면 아시겠지만 SSL 설정을 해주셔야합니다. 앞선 포스팅을 참고해주세요. 2017.06.23 23:25 신고
댓글쓰기 폼