Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

用Golang发起和接收请求 #64

Open
kevinyan815 opened this issue Jul 31, 2021 · 0 comments
Open

用Golang发起和接收请求 #64

kevinyan815 opened this issue Jul 31, 2021 · 0 comments

Comments

@kevinyan815
Copy link
Owner

kevinyan815 commented Jul 31, 2021

读取请求

接收请求涉及的内容较多,在我公众号的文章中已经有详细概况总结过,具体查看文章:「深入学习解析HTTP请求

发起请求

func httpRequest(method string, url string, options ...*Option) (code int, content string, err error) {
	start := time.Now()

	reqOpts := defaultRequestOptions() // 默认的请求选项
	for _, opt := range options {      // 在reqOpts上应用通过options设置的选项
		opt.apply(reqOpts)
	}
	// 创建请求对象
	req, err := http.NewRequest(method, url, strings.NewReader(reqOpts.data))
	// 记录请求日志
	defer func() {
		dur := int64(time.Since(start) / time.Second)
		if dur >= 500 {
			log.Println("Http"+method, url, "in", reqOpts.data, "out", content, "err", err, "dur/ms", dur)
		} else {
			log.Println("Http"+method, url, "in", reqOpts.data, "out", content, "err", err, "dur/ms", dur)
		}
	}()
	defer req.Body.Close()

	if len(reqOpts.headers) != 0 { // 设置请求头
		for key, value := range reqOpts.headers {
			req.Header.Add(key, value)
		}
	}
	if err != nil {
		return
	}
	// 发起请求
	client := &http.Client{Timeout: reqOpts.timeout}
	resp, error := client.Do(req)
	if error != nil {
		return 0, "", error
	}
	// 解析响应
	defer resp.Body.Close()
	code = resp.StatusCode
	result, _ := ioutil.ReadAll(resp.Body)
	content = string(result)

	return
}

// 发起GET请求
func HttpGet(url string, options ...*Option) (code int, content string, err error) {
	return httpRequest("GET", url, options...)
}

// 发起POST请求,请求头指定Content-Type: application/json
func HttpJsonPost(url string, data string, timeout time.Duration) (code int, content string, err error) {
	headers := map[string]string{
		"Content-Type": "application/json",
	}
	code, content, err = httpRequest(
		"POST", url, WithTimeout(timeout), WithHeaders(headers), WithData(data))

	return
}

由于HTTP请求时可以设置的选项较多,不固定,所以上面的代码学习gRPC对dialOptions的实现,使用了Options设计模式优雅地解决了不定参数的传递。

// 针对可选的HTTP请求配置项,模仿gRPC使用的Options设计模式实现
type requestOption struct {
	timeout time.Duration
	data    string
	headers map[string]string
}

type Option struct {
	apply func(option *requestOption)
}

func defaultRequestOptions() *requestOption {
	return &requestOption{ // 默认请求选项
		timeout: 5 * time.Second,
		data:    "",
		headers: nil,
	}
}

func WithTimeout(timeout time.Duration) *Option {
	return &Option{
		apply: func(option *requestOption) {
			option.timeout = timeout
		},
	}
}

详细代码,请查看仓库里的代码:https://github.com/kevinyan815/gocookbook/blob/master/codes/httptool/http_util.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant