Goのhttp clientを試す
Goのhttp clientを試してみたメモです。
Goでhttp clientはどう書くのか調べてみると、
標準のnet/httpパッケージが十分高機能で使えるようでした。
http - The Go Programming Language
GET, POST(form), POST(json)をそれぞれ試してみます。
GET
GETを受けるサーバを作成します。
リクエストのメソッド、ヘッダ、パラメータを標準出力するようにしました。
リクエスト受信後に文字列をレスポンスとして返します。
server.go
func handleDog(w http.ResponseWriter, req *http.Request) { // header method := req.Method fmt.Println("[method] " + method) for k, v := range req.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // GET if method == "GET" { req.ParseForm() for k, v := range req.Form { fmt.Print("[param] " + k) fmt.Println(": " + strings.Join(v, ",")) } fmt.Fprint(w, "Recieved Get request!!") } }
http.HandleFunc()でルーティングを行います。
"/dog"でアクセスされた場合に,handleDog()へハンドリングします。
http.ListenAndServe()を実行するとサーバが起動します。
port 8080で待ち受けます。
func main() { http.HandleFunc("/dog", handleDog) http.ListenAndServe(":8080", nil) }
GETするクライアントを作成します。
http.Get()でURLを指定するだけなので、シンプルです。
レスポンスのステータス、ヘッダ、ボディを標準出力するようにしてみます。
client.go
func get() { // Get request res, err := http.Get("http://localhost:8080/dog?id=123&order=desc") if err != nil { log.Fatal(err) } // header fmt.Printf("[status] %d\n", res.StatusCode) for k, v := range res.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // body defer res.Body.Close() body, error := ioutil.ReadAll(res.Body) if error != nil { log.Fatal(error) } fmt.Println("[body] " + string(body)) }
実行してみます。
サーバ側ログ
$ go run server.go [method] GET [header] User-Agent: Go-http-client/1.1 [header] Accept-Encoding: gzip [param] id: 123 [param] order: desc
クライアント側ログ
$ go run client.go [status] 200 [header] Date: Tue, 24 Apr 2018 00:07:14 GMT [header] Content-Length: 22 [header] Content-Type: text/plain; charset=utf-8 [body] Recieved Get request!!
POST(form)
POSTでformを送信してみます。
同様にPOSTを受けるサーバを作成します。
リクエストのメソッド、ヘッダ、パラメータ、生のform、URL decodeしたformを標準出力するようにしました。
リクエスト受信後に文字列をレスポンスとして返します。
server.go
func handleDog(w http.ResponseWriter, req *http.Request) { // header method := req.Method fmt.Println("[method] " + method) for k, v := range req.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // POST (form) if method == "POST" { defer req.Body.Close() body, err := ioutil.ReadAll(req.Body) if err != nil { log.Fatal(err) } fmt.Println("[request body row] " + string(body)) decoded, error := url.QueryUnescape(string(body)) if error != nil { log.Fatal(error) } fmt.Println("[request body decoded] ", decoded) fmt.Fprint(w, "Recieved Post(form) request!!") } }
POSTするクライアントを作成します。
formの内容はhttp.PostForm()の引数に渡すだけです。
レスポンスのステータス、ヘッダ、ボディを標準出力するようにしてみます。
client.go
func postAsForm() { // form values values := url.Values{} values.Add("id", "123") values.Add("name", "ポメラニアン") values.Encode() res, err := http.PostForm("http://localhost:8080/dog", values) if err != nil { log.Fatal(err) } // header fmt.Printf("[status] %d\n", res.StatusCode) for k, v := range res.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // body defer res.Body.Close() body, error := ioutil.ReadAll(res.Body) if error != nil { log.Fatal(error) } fmt.Println("[body] " + string(body)) }
実行してみます。
サーバ側ログ
$ go run server.go [method] POST [header] User-Agent: Go-http-client/1.1 [header] Content-Length: 66 [header] Content-Type: application/x-www-form-urlencoded [header] Accept-Encoding: gzip [request body row] id=123&name=%E3%83%9D%E3%83%A1%E3%83%A9%E3%83%8B%E3%82%A2%E3%83%B3 [request body decoded] id=123&name=ポメラニアン
クライアント側ログ
$ go run client.go [status] 200 [header] Date: Tue, 24 Apr 2018 00:07:14 GMT [header] Content-Length: 29 [header] Content-Type: text/plain; charset=utf-8 [body] Recieved Post(form) request!!
POST(json)
POSTでjsonを送信してみます。
下記のDogの構造体を作成し、jsonシリアライズしてPOST送信してみます。
tagで`json:"xxx"`と記述すると、jsonパッケージでのシリアライズ・デシリアライズでjsonのキーとして使用されます。
type Dog struct { Id int `json:"id"` Name string `json:"name"` }
POSTを受けるサーバを作成します。
リクエストのメソッド、ヘッダ、パラメータ、生のbody、デシリアライズしたbodyを出力するようにしました。
リクエスト受信後に文字列をレスポンスとして返します。
server.go
func handleDogJson(w http.ResponseWriter, req *http.Request) { // header method := req.Method fmt.Println("[method] " + method) for k, v := range req.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // POST (json) if method == "POST" { defer req.Body.Close() body, err := ioutil.ReadAll(req.Body) if err != nil { log.Fatal(err) } fmt.Println("[request body row] " + string(body)) // Unmarshal var dog Dog error := json.Unmarshal(body, &dog) if error != nil { log.Fatal(error) } fmt.Printf("[request body decoded] %+v\n", dog) fmt.Fprint(w, "Recieved Post(json) request!!") } }
POSTするクライアントを作成します。
Dogをjsonシリアライズし、http.Post()の第2引数でContentTypeとして"application/json"を指定します。
レスポンスを標準出力するようにしてみます。
client.go
func postAsJson() { // json values values, err := json.Marshal(Dog{Id: 2, Name: "柴犬"}) res, err := http.Post("http://localhost:8080/dog_json", "application/json", bytes.NewBuffer(values)) if err != nil { log.Fatal(err) } // header fmt.Printf("[status] %d\n", res.StatusCode) for k, v := range res.Header { fmt.Print("[header] " + k) fmt.Println(": " + strings.Join(v, ",")) } // body defer res.Body.Close() body, error := ioutil.ReadAll(res.Body) if error != nil { log.Fatal(error) } fmt.Println("[body] " + string(body)) }
実行してみます。
サーバ側ログ
$ go run server.go [method] POST [header] User-Agent: Go-http-client/1.1 [header] Content-Length: 24 [header] Content-Type: application/json [header] Accept-Encoding: gzip [request body row] {"id":2,"name":"柴犬"} [request body decoded] {Id:2 Name:柴犬}
クライアント側ログ
$ go run client.go [status] 200 [header] Date: Tue, 24 Apr 2018 00:07:14 GMT [header] Content-Length: 29 [header] Content-Type: text/plain; charset=utf-8 [body] Recieved Post(json) request!!
コードは下記にあげました。
github.com
終わり。