Skip to content
tony9527167 edited this page Aug 3, 2025 · 4 revisions

设计之初对内置 net/http 包简单封装,为了支持链式调用(Method Chaining)和设置 HTTP 连接超时简单,后续加上 golang/mock 支持。

mock 示例见 https://github.com/giant-stone/go/blob/master/ghttp/ghttp_test.go#L15

用法示例

链式调用

const (
	DefaultTimeoutInSecs = time.Second * 5
)

func ExampleNew() {
	glogging.Install([]string{"stderr"}, "debug", "")

	fullurl := "https://httpbin.org/post"
	postData := []byte(`{"msg":"hello"}`)
	req := ghttp.New().
		SetRandomUserAgent(true).
		SetTimeout(time.Second * 3).
		SetRequestMethod("POST").
		SetUri(fullurl).
		SetProxy(os.Getenv("HTTPS_PROXY")).
		SetPostBody(postData)
	err := req.Send()
	ghttp.CheckRequestErr(fullurl, req.RespStatus, req.RespBody, err)
	fmt.Println(req.RespStatus)
	// Output: 200
}

两种 POST 请求

application/x-www-form-urlencoded POST 方式

type FieldForm struct {
	Id   string
	Name string
}
type Rs struct {
	Form *FieldForm `json:"form"`
}

// ExampleHttpRequest_SetPostBody show howto POST in application/x-www-form-urlencoded
func ExampleHttpRequest_SetPostBody() {
	glogging.Install([]string{"stderr"}, "debug", "")

	rq := ghttp.New().
		SetRequestMethod("POST").
		SetUri("https://httpbin.org/post").
		SetTimeout(time.Second * 5)

	form := url.Values{}
	form.Add("id", fmt.Sprintf("%d", 123))
	form.Add("name", "foo")
	rq.SetHeader("Content-Type", "application/x-www-form-urlencoded")

	rqBody := []byte(form.Encode())

	rq.SetPostBody(rqBody)
	err := rq.Send()
	gutil.ExitOnErr(err)

	want := &FieldForm{
		Id:   form.Get("id"),
		Name: form.Get("name"),
	}
	var rs Rs
	err = json.Unmarshal(rq.RespBody, &rs)
	gutil.ExitOnErr(err)

	fmt.Println(rq.RespStatus)
	fmt.Println(want.Id == rs.Form.Id && want.Name == rs.Form.Name)
	// Output:
	// 200
	// true
}

multipart/form-data POST 方式

// ExampleHttpRequest_SetPostBody show howto POST in multipart/form-data
func ExampleHttpRequest_SetPostBody_multipart() {
	glogging.Install([]string{"stderr"}, "debug", "")
	// use default implement avoid conflict with ghttp/ghttp_test.go
	ghttp.UseImpl(nil)

	var err error

	gh := ghttp.New().SetTimeout(time.Second * 5)

	var b bytes.Buffer
	w := multipart.NewWriter(&b)

	err = ghttp.AppendMultipartFormData(w, "myfile", "myfile.data", []byte(`hello 中文`))
	gutil.ExitOnErr(err)

	err = ghttp.AppendMultipartFormData(w, "myfile2", "myfile2.data", []byte(`foo\nbar`))
	gutil.ExitOnErr(err)

	err = w.WriteField("id", "123")
	gutil.ExitOnErr(err)

	err = w.Close()
	gutil.ExitOnErr(err)

	rq, err := http.NewRequest("POST", "https://httpbin.org/post", bytes.NewReader(b.Bytes()))
	gutil.ExitOnErr(err)

	rq.Header.Add("Content-Type", w.FormDataContentType())
	rs, err := gh.Do(rq)
	gutil.ExitOnErr(err)

	rsBody, err := ghttp.ReadBody(rs)
	gutil.ExitOnErr(err)

	fmt.Println(rs.StatusCode)
	fmt.Println(len(rsBody) > 0)
	// Output:
	// 200
	// true
}

POST JSON

func ExampleHttpRequest_DoAndSetPostBody() {
	glogging.Install([]string{"stderr"}, "debug", "")

	paramsPost := map[string]interface{}{
		"msg": "hello",
	}
	fullurl := "https://httpbin.org/post"
	dataPostBody, _ := json.Marshal(paramsPost)

	rq := ghttp.New().
		SetRequestMethod("POST").
		SetUri(fullurl)

	rq.SetPostBody(dataPostBody)

	resp, err := ghttp.NewWithCtx(context.Background()).
		SetTimeout(DefaultTimeoutInSecs).
		Do(rq.GenerateRequest())

	if err != nil {
		log.Fatal(err)
	}

	dataRsBody, err := ghttp.ReadBody(resp)
	if err != nil {
		log.Fatal(err)
	}

	type Rs struct {
		Data string
	}
	rs := &Rs{}
	err = json.Unmarshal(dataRsBody, rs)
	if err != nil {
		log.Fatal(err)
	}

	ghttp.CheckRequestErr(fullurl, resp.StatusCode, dataRsBody, err)
	fmt.Println(resp.StatusCode)
	fmt.Println(rs.Data)
	// Output: 200
	// {"msg":"hello"}
}

可重复读 response body

func ExampleReadBody() {
	glogging.Install([]string{"stderr"}, "error", "")

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel()

	gh := ghttp.NewWithCtx(ctx).SetUri("https://httpbin.org/uuid")
	rs, err := gh.Do(gh.GenerateRequest())
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i < 3; i++ {
		body, err := ghttp.ReadBody(rs)
		if err != nil {
			log.Fatal(err)
		}
		// something looks like `{"uuid": "2ae860ed-47da-4adb-9373-128f3eb4ce71"}`
		fmt.Println(len(body))
	}

	// Output: 53
	// 53
	// 53
}

Clone this wiki locally