DEV Community

D
D

Posted on

Golang (heroku) で LINE Bot 作ってみる

追記 (2016/04/12)
Botの機能追加+ソースコードリファクタリングしてるうちにライブラリ化しました
https://github.com/dongri/line-bot-sdk-go
今のところ、text, sticker, image, video簡単に送れます。プロフィールも簡単に取得可能です。


まずコードから。メッセージを送るとそのメッセージをそのまま返すサンプル。下にちゃんとしたやつもあります。

 package main import ( "bytes" "encoding/json" "fmt" "io/ioutil" "log" "net/http" "net/url" "os" "time" ) // ReceivedMessage ... type ReceivedMessage struct { Result []Result `json:"result"` } // Result ... type Result struct { ID string `json:"id"` From string `json:"from"` FromChannel int `json:"fromChannel"` To []string `json:"to"` ToChannel int `json:"toChannel"` EventType string `json:"eventType"` Content Content `json:"content"` } // SendMessage .. type SendMessage struct { To []string `json:"to"` ToChannel int `json:"toChannel"` EventType string `json:"eventType"` Content Content `json:"content"` } // Content ... type Content struct { ID string `json:"id"` ContentType int `json:"contentType"` From string `json:"from"` CreatedTime int `json:"createdTime"` To []string `json:"to"` ToType int `json:"toType"` Text string `json:"text"` } // const ... const ( EndPoint = "https://trialbot-api.line.me" ToChannel = 1383378250 EventType = "138311608800106203" ) func main() { http.HandleFunc("/", helloHandler) http.HandleFunc("/callback", callbackHandler) port := os.Getenv("PORT") addr := fmt.Sprintf(":%s", port) http.ListenAndServe(addr, nil) } func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, LINE Bot") } func callbackHandler(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) var m ReceivedMessage err := decoder.Decode(&m) if err != nil { log.Println(err) } apiURI := EndPoint + "/v1/events" for _, result := range m.Result { from := result.Content.From text := result.Content.Text content := new(Content) content.ContentType = result.Content.ContentType content.ToType = result.Content.ToType content.Text = text request(apiURI, "POST", []string{from}, *content) } } func request(endpointURL string, method string, to []string, content Content) { m := &SendMessage{} m.To = to m.ToChannel = ToChannel m.EventType = EventType m.Content = content b, err := json.Marshal(m) if err != nil { log.Print(err) } req, err := http.NewRequest(method, endpointURL, bytes.NewBuffer(b)) if err != nil { log.Print(err) } req = setHeader(req) client := &http.Client{ Transport: &http.Transport{Proxy: http.ProxyURL(getProxyURL())}, Timeout: time.Duration(30 * time.Second), } res, err := client.Do(req) if err != nil { log.Print(err) } defer res.Body.Close() var result map[string]interface{} body, err := ioutil.ReadAll(res.Body) if err != nil { log.Print(err) } if err := json.Unmarshal(body, &result); err != nil { log.Print(err) } log.Print(result) } func setHeader(req *http.Request) *http.Request { req.Header.Add("Content-Type", "application/json; charset=UTF-8") req.Header.Add("X-Line-ChannelID", os.Getenv("ChannelID")) req.Header.Add("X-Line-ChannelSecret", os.Getenv("ChannelSecret")) req.Header.Add("X-Line-Trusted-User-With-ACL", os.Getenv("MID")) return req } func getProxyURL() *url.URL { proxyURL, err := url.Parse(os.Getenv("ProxyURL")) if err != nil { log.Print(err) } return proxyURL } 
Enter fullscreen mode Exit fullscreen mode

やってるうちに詰まったところをまとめ

  1. callback URLはhttpsのみ
    今まで簡単なサンプルは自前のサーバーでやってて、当然https対応してない。しかしLINE Botのcallbackはhttpsにportを443に指定しないといけない。let's encryptでhttps化。しかしcallbackにリクエストが来ない。herokuでなんとかすると決める。

  2. 許可したipしかsendmessageできない
    herokuにデプロイしてログを見てるとipで弾かれてる。指定したipでしかpostできないみたい。bot管理ページにwhitelistがあってそこに自分のサーバーip追加しないといけないらしい。しかし、herokuはデプロイする度にipが変わってて使いものにならない。こちらの記事( http://qiita.com/yuya_takeyama/items/0660a59d13e2cd0b2516 )にもかいてあるようにproxyを使ってproxyのipを指定すれば解決できる。

  3. contentTypeで弾かれてる
    headerのcontent-typeかと思ったがメッセージcontentのcontentTypeをちゃんと指定しないといけない

  4. 先着1万と書いてあるのが怪しい
    1万枠外でもBotの登録できるんじゃないかと疑ってる。自分のアカウントは昨日早めに登録したので、使えるが、1アカウント1Botの制限のため今日嫁のアカウントで登録したけど、callbackが来ない。

とりあえず電車でも haskell

Screen Shot 2016-04-08 at 11.21.08 PM.png

Screenshot_20160408-233023.png

Top comments (0)