Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

追記 (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
}

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

  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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away