前言
无论是微服务还是单体架构等,服务间都有相互通信的时候,而最直接的通信方法就是 HTTP
调用,本文将会介绍在 Go
语言里,如何进行 HTTP
调用,并举例说明。
前置知识
HTTP
调用需要通过http
包里的Client
结构体里的Do
方法去实现,因此需要先声明一个Client
结构体变量,该结构体可以设置超时时间等配置。- 对于一个请求里的
URL
,查询参数,请求method
等参数,需要http
包里的Request
结构体去封装。我们可以通过NewRequestWithContext
或NewRequest
函数获取一个基础的Request
结构体指针变量。NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error)
- 参数
ctx
为Context
的接口类型,任意实现Context
接口的自定义类型都可以作为此参数传递。 - 参数
method
为HTTP
方法参数,可选值有GET
、POST
、DELETE
、PUT
等。 - 参数
url
为接口的请求路径。 - 参数
body
,为请求体参数。
- 参数
- 通过
client.Do(req)
方法调用之后,返回值有(*Response, error)
,第一个是响应结构体参数,第二个是错误参数。通过读取Response
的body
的值,可以获取接口的响应体。
GET 请求
代码语言:go复制import (
"context"
"fmt"
"io"
"net/http"
)
func main() {
client := http.Client{}
request, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://localhost:8080/user?name=tom", nil)
if err != nil {
return
}
request.Header.Set("headerParam", "header")
resp, err := client.Do(request)
if err != nil {
fmt.Println(err)
return
}
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return
}
defer resp.Body.Close()
fmt.Println(string(bytes)) // {"code":0,"data":{"list":[{"name":"小明","age":20},{"name":"小红","age":18}]},"message":"success"}
}
- 需要携带查询参数时,可以直接拼接在
url
字符串上面。 header
参数可以通过 request 结构体的Header
字段的set
方法或add
方法进行设置。- HTTP 请求响应码可以通过
Response
的StatusCode
字段进行查看。 - 接口请求成功之后,通过
io.ReadAll
方法,读取resp.Body
响应体信息。 - 除了直接在
url
上拼接query
参数的方式,我们还可以通过以下方式进行添加query
参数:
params := url.Values{}
rawUrl, err := url.Parse("http://localhost:8080/user")
if err != nil {
return
}
params.Set("name", "tom")
rawUrl.RawQuery = params.Encode()
u := rawUrl.String()
通过 url.Values
结构体的 set
方法设置 query参数,url
通过 url.Parse
函数生成一个 URL
结构体指针变量,rawUrl.RawQuery = params.Encode()
通过这行代码将 query
参数和 url
进行绑定,最后通过 String()
方法将 url
转换成 string
类型。
POST 请求
发起 HTTP
POST
请求时,携带 json
格式的 body
参数是最常见的,这是因为 json
格式的参数可读性好,对于层级结构较为复杂的数据也能应对,并且这符合 RestFul API
的规范。因此以下的示例为:
发送 HTTP
POST
请求,并携带 json
类型的 body
参数。
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
func main() {
client := http.Client{}
user := User{
Username: "123456",
Password: "12346",
}
dataByte, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
}
bodyReader := bytes.NewReader(dataByte)
request, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "http://localhost:8080/user", bodyReader)
if err != nil {
return
}
request.Header.Set("Content-Type", "application/json")
resp, err := client.Do(request)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("statusCode: ", resp.StatusCode)
body, err := io.ReadAll(resp.Body)
if err != nil {
return
}
defer resp.Body.Close()
fmt.Println(string(body))
}
- 首先定义
User
结构体,创建结构体变量 user,通过json.Marshal
函数,将user
转成[]byte
数据,然后通过bytes.NewReader
函数,将[]byte
数据转成Reader
指针变量。 http.NewRequestWithContext
函数,最后一个参数是为body
参数,接收的变量类型是Reader
接口的实现体。第一步将user
转成Reader
指针变量就是为了在这里进行传递。- 传递
json
类型的body
参数,需要在请求头参数里设置Content-Type
的值为application/json
。 - 如果是发送
application/x-www-form-urlencoded
类型的表单数据,需要改写body
参数的生成代码:
小结
本文首先介绍了在 Go
语言里如何进行 HTTP
调用,需要通过 http
包里的 Client
结构体变量,调用其方法 Do
进行 HTTP
调用,在 HTTP
调用前,需要通过 http
包里的 Request
结构体封装请求路径和请求参数。然后通过 GET
请求案例讲述了 query
参数和 header
参数如何设置,以及响应体的获取方法。
最后通过 POST
请求,介绍了如何传递 json
类型和 application/x-www-form-urlencoded
类型的 body
参数。对于 HTTP
中的 query
参数和 body
参数的如何传递,然后给出示例。虽然举的例子是 GET
和 POST
请求,如果想要调用 PUT
、DELETE
等请求,只需要在 NewRequestWithContext
函数中,指定第二个参数为 http.MethodPut
、http.MethodDelete
等就行。
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表