7 http-client开发
所谓的 http-client 开发就是需要对服务方发起请求http.Client
,如何在我们的 client 上提交数据。
提交数据的几种方式
-
通过 RUL 提交参数
-
通过 HTTP 协议进行提交
-
GET/POST
-
HEADER
-
BODY
-
7.1 客户端 Get 请求方式
1.编写一个 server 端
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
addr := ":8888"
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method)
fmt.Println("url:", r.URL)
fmt.Println("protocol:", r.Proto)
fmt.Println("Body:")
io.Copy(os.Stdout, r.Body)
fmt.Fprintln(rw, time.Now().Format("2006-01-02 15-04-05"))
})
http.ListenAndServe(addr, nil)
}
执行
[11:33:14 root@go webrequest]#go run main.go
2.编写客户端
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
// 请求本机的 http://127.0.0.1:8888/
res, err := http.Get("http://127.0.0.1:8888/")
if err != nil {
fmt.Println(err)
return
}
// 将请求到的服务器端 body 信息输出
io.Copy(os.Stdout, res.Body)
}
执行客户端
[11:38:35 root@go webclient]#go run main.go
2021-07-23 11-38-41
此时服务器端输出 客户端的请求信息
[11:33:14 root@go webrequest]#go run main.go
method: GET # 请求方法
url: / # 请求 url
protocol: HTTP/1.1 # 请求 http 协议
Body: {} # 客户端 body 信息为空
但是这个时候如果我客户端需要提交参数我该怎么提交,我们都知道 GET 方法的提交参数信息是在 URL 的位置进行提交,所以我们只需要在客户端的请求 URL 中提交即可
客户端提交参数如下图
然后再次执行客户端,此时服务器端就会获取到客户端的请求信息
7.2 客户端 Head 请求方式
Head(url string) (resp *http.Response, err error)
客户端代码
package main
import (
"io"
"log"
"net/http"
"os"
"os/exec"
)
func main() {
// 通过 http.Head 传入要访问的 url 请求
resq, err := http.Head("http://127.0.0.1:8888/?x=1&y=2")
if err != nil {
log.Println(err)
return
}
// 终端输出
io.Copy(os.Stdout, resq.Body)
}
服务器端还是使用上面的代码
然后执行结果,服务器端输出请求方式为 head
7.3 客户端 POST 请求方式
在 post 请求的时候有两种方式:
-
比较常见的
x-www-form-urlencode
-
自定义类型如 json 格式
7.3.1 PostForm 请求方式
PostForm(url string, data url.Values) (resp *http.Response, err error)
客户端代码:
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func main() {
// 赋值 values 为 url.Values 结构体
values := url.Values{}
// 添加请求数据
values.Add("x", "1")
values.Add("x", "2")
// 更新请求数据
values.Set("y", "1")
values.Set("y", "2")
// 请求 URL http://127.0.0.1:8888/ ,请求数据 values
resq, err := http.PostForm("http://127.0.0.1:8888/", values)
if err != nil {
fmt.Println(err)
return
}
io.Copy(os.Stdout, resq.Body)
}
服务器端代码依旧不变,执行结果,body 拿到数据
7.3.2 JSON 格式请求
自定义类型 json 格式请求,需要使用到 Post()
func http.Post(url string, contentType string, body io.Reader) (resp *http.Response, err error)
编写 test.json
文件
{
"a":1,
"b":2
}
客户端代码
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
// 打开 test.json 文件
f, _ := os.Open("test.json")
// 将 json 文件通过 http.Post 传递给 http://127.0.0.1:8888/ contentType(内容类型为 json)
resq, err := http.Post("http://127.0.0.1:8888/", "application/json", f)
if err != nil {
fmt.Println(err)
return
}
io.Copy(os.Stdout, resq.Body)
}
服务器端代码不变,最终执行并解析
但是我们现在有一个问题就是,假如我们想提交一个 json 文件还需要创建一个文件并编写内容,这样是不是特别麻烦,那么我们有没有比较简单的方法来实现,比如实现了一个 read 接口,然后又在内存里面呢?其实这个问题更是一个能不能在内存中对字符串进行操作,我们都知道在 strings,bytes
两个包中有大量对字符串的操作,由此引出下面操作
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
// 通过 strings.NewReader 的同时直接进行写入我们的 json 对象
// 把 reader 变量变成了类似一个的流对象
reader := strings.NewReader(`
{"a":"x"}
`)
// 将 json 文件通过 http.Post 传递给 http://127.0.0.1:8888/ contentType(内容类型为 json),传入 reader 变量
resq, err := http.Post("http://127.0.0.1:8888/", "application/json", reader)
if err != nil {
fmt.Println(err)
return
}
io.Copy(os.Stdout, resq.Body)
}
执行
7.4 客户端文件上传
我们需要把我文件读取到内存中
package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
// 初始化一个新的 buffer 缓冲区
buffer := bytes.NewBuffer(nil)
// 创建一个 multipart.Writer 对象,因为再 io.Copy 中第一个参数接收的是 writer 对象
writer := multipart.NewWriter(buffer)
// 然后上传到服务器上的新文件名 xx.json
filewriter, err := writer.CreateFormFile("z", "xx.json")
if err != nil {
fmt.Println(err)
return
}
// 打开文件 test.json
f, _ := os.Open("test.json")
// 然后把 test.json 文件中的内容读取并写入到 filewriter 变量中,filewriter 是等会再服务器上传后的文件
io.Copy(filewriter, f)
// 关闭写入
writer.Close()
resq, err := http.Post("http://127.0.0.1:8888/", "multipart/form-data", buffer)
if err != nil {
fmt.Println(err)
return
}
// 在终端输出请求到的 服务器端 body
io.Copy(os.Stdout, resq.Body)
}
服务器端代码不变
通过执行从 body 信息能够观察到文件已经上传