gocookbook
gocookbook copied to clipboard
用Golang发起和接收请求
读取请求
接收请求涉及的内容较多,在我公众号的文章中已经有详细概况总结过,具体查看文章:「深入学习解析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