emahiro/b.log

日々の勉強の記録とか育児の記録とか。

goでのhttpの書き方あれこれ

goの標準

goでhttpの処理を書きたいときはnet/httpパッケージを使う。
強力なパッケージなので、基本これを使うで、やりたいことの殆どはまかなえてしまうと思う

http.Get(url)

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    resp, err := http.Get("http://www.google.co.jp")
    if err != nil {
        fmt.Printf("err: %v", err)
    }
    defer resp.Body.Close()

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("ioutil err: %v", err)
    }
    fmt.Printf("html: %v", string(b))
}

http.NewRequest(url)

単純にGetをするだけであれば http.Get(url) で事足りると思われるが、その他のMethodにも対応させるために、httpクライアントを明示的に作ることも可能

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    req, err := http.NewRequest("GET", "http://www.google.co.jp", nil)
    if err != nil {
        fmt.Printf("new request err: %v", err)
    }
    client := http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("request response err: %v", err)
    }

    defer resp.Body.Close()

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("ioutil err: %v", err)
    }
    fmt.Printf("html: %v", string(b))
}

GAEの標準

GAE/Goでhttpを書きたいときにはちょっと1つ考慮しておかなければいけないことがある。

  • GAE/Goでは、GAEのContextを使わないといけない
  • 通常のリクエストからGAEのContextを作成し、それを使ってhttpのrequest/responseを実装する
package main

import (
    "net/http"

    "io/ioutil"

    "google.golang.org/appengine"
    "google.golang.org/appengine/log"
    "google.golang.org/appengine/urlfetch"
)

func init() {
    http.HandleFunc("/", SampleHandler)
}

func SampleHandler(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r) // GAEのContextを作成する
    httpClient := urlfetch.Client(ctx)
    resp, err := httpClient.Get("http://www.google.co.jp")
    if err != nil {
        log.Debugf(ctx, "html: %v", err)
    }
    defer resp.Body.Close()
    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Debugf(ctx, "html: %v", err)
    }
    log.Debugf(ctx, "html: %v", string(b))
}

ハマったところ

  • gaeのプロジェクトの最小構成単位はhandlerを受け付けるgoのファイルとapp.yamlがあること。
  • しかし、この2つのファイルは同じ階層においては行けない
- my-project
    - app.yaml
    - src
        - main.go

というディレクトリ構成にする必要がある。

  • gaeではmain関数でなく init() を使う。
  • main() を使っていた最中にずっと起動後 localhost:8080 に繋いでも 404 page not found が返ってきてしまっていた。
  • gaeのhttpのHandlerには http.ListenAndServe() メソッドは使わない。