0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

メモ:golangでのrequest(cencelあり)

Posted at
  • 忘れがちになる、golangでの外部リクエストの方法についてちょっとメモを残す。
  • いくつか方法はある(http.Getを使うであるとか)のだが、ここでは外部のAPIへGet/Postでリクエストすることを想定するので、ヘッダの操作なでもする。あと、リクエストタイムアウトなどの要因で応答がある前にキャンセルもしたい。
main.go
package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"time"
)

type localClient struct {
	client *http.Client
}

func main() {
	lc := &localClient{}

	// ダミーのmockServerを用意している。実際の処理ではいらない
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Print(r.URL, r.Header, r.Body) // requestの内容を確認するためにログ出力
		time.Sleep(10 * time.Second)	// request cancelを試すためにわざと応答をsleepしている
		fmt.Fprintln(w, "Hello, client")
	}))
	defer ts.Close()

	// context.Backgroundでcontextを生成している
	ctx, cancel := context.WithCancel(context.Background())

	// client側の処理
	lc.client = &http.Client{}

	// request bodyの準備
	values := url.Values{}
	values.Set("token", "testtoken")

	req, err := http.NewRequest(
		http.MethodPost,
		ts.URL, // mockServerへのrequestにしてあるが実際の処理ではちゃんとendpointを書く
		strings.NewReader(values.Encode()),
	)
	if err != nil {
		panic(err)
	}

	req = req.WithContext(ctx)

	// request Headerを指定
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	// response受け取り用のchannel
	ch := make(chan []byte)
	var res []byte

	// requestのgoroutine
	go func() {
		resp, err := lc.request(req)
		if err != nil {
			ch <- nil
			return
		}
		ch <- resp
	}()

	// 5秒でcancelしている
	go func() {
		time.Sleep(5 * time.Second)
		cancel()
	}()

	// requestのgoroutineがchannelへデータを入れるまでwaitする
	res = <-ch

	log.Print("response:", string(res))
}

func (lc localClient) request(req *http.Request) ([]byte, error) {
	log.Print("start request")

	resp, err := lc.client.Do(req)
	if err != nil {
		log.Print("error request :", err)
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Print("error response body")
		return nil, err
	}

	log.Print("end request")

	return body, nil
}
  • ざっと書いてはみたが、ちょっとcencelの方法に疑問が残るので、もう少し調べて修正するかも。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?