【Golang 接口自动化02】使用标准库net/http发送Post请求

目录

写在前面

发送Post请求

示例代码

源码分析

Post请求参数解析

响应数据解析

验证

发送Json/XMl

Json请求示例代码

xml请求示例代码

总结

资料获取方法


写在前面

上一篇我们介绍了使用 net/http 发送get请求,因为考虑到篇幅问题,把Post单独拎了出来,我们在这一篇一起从源码来了解一下Golang的Post请求。

发送Post请求

net/http发送Post请求很容易,下面的代码我们和Get请求一样,把响应的内容的信息打印出来了,细心的朋友可能会发现,在参数传递、和结果解析时用了三种不同的方式,我们将在后面进行解析。

示例代码

python 复制代码
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
)

func main() {
	resp, err := http.Post("http://httpbin.org/post",
		"application/x-www-form-urlencoded",
		strings.NewReader("name=Detector&mobile=1xxxxxxxx"))
	if err != nil {
		fmt.Println(err)
		return
	}

	defer resp.Body.Close()
	headers := resp.Header
	// headers 打印报文头部信息
	for k, v := range headers {
		fmt.Printf("%v, %v\n", k, v) // %v 打印interfac{}的值
	}

	// 打印响应信息内容
	fmt.Printf("响应状态:%s,响应码: %d\n", resp.Status, resp.StatusCode)
	fmt.Printf("协议:%s\n", resp.Proto)
	fmt.Printf("响应内容长度: %d\n", resp.ContentLength)
	fmt.Printf("编码格式:%v\n", resp.TransferEncoding) // 未指定时为空
	fmt.Printf("是否压缩:%t\n", resp.Uncompressed)
	fmt.Println(reflect.TypeOf(resp.Body)) // *http.gzipReader
	fmt.Println(resp.Body)

	buf := bytes.NewBuffer(make([]byte, 0, 512))
	length, _ := buf.ReadFrom(resp.Body)
	fmt.Println(len(buf.Bytes()))
	fmt.Println(length)
	fmt.Println(string(buf.Bytes()))
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}

源码分析

Post请求参数解析

我们首先来看一下C:\Go\src\net\http\client.go中Post和Get请求的源码:

python 复制代码
func Get(url string) (resp *Response, err error) {
	return DefaultClient.Get(url)
}
python 复制代码
func Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
	return DefaultClient.Post(url, contentType, body)
}

从上面的定义可以看出,Post请求的参数比Get复杂一些,不仅要传递string类型contentType还有传递io.Reader类型的body体。可能有的小伙伴就有疑问了-- io.Reader类型的body体是不是意味着我们一定要使用io.Reader模块来获取数据呢?

答案当然是否定的。

我们通过阅读源码,来找想要的答案。

找到其最小粒度的接口是一个比较好的手段,io.Reader最小粒度的接口的定义在C:\Go\src\io\io.go中:

python 复制代码
type Reader interface {
	Read(p []byte) (n int, err error)
}

在我前面的一篇博客【Golang】基础10 Go语言最精妙的设计--interface中学习过 interface,其中有两句话是这样的:

interface类型定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象。

针对io.Reader的定义翻译一下就是,只要实现了Read(p []byte) (n int, err error)方法的类型,就可以存储io.Reader,从而作为Post请求的Body参数。

我们接着来看看响应resp中数据的定义。

响应数据解析

在上一篇我们对http请求中的数据进行了介绍,这一次我们针对resp.Body进行展开。

在C:\Go\src\net\http\response.go中我们可以看到它的类型Body io.ReadCloser,在C:\Go\src\io\io.go中我们可以看到对应的定义是这样的:

python 复制代码
type ReadCloser interface {
	Reader
	Closer
}

而Reader就是我们上面分析的过的请求body定义的Reader,而Closer是一个error类型:

python 复制代码
type Closer interface {
	Close() error
}

根据我们上面的结论-- 定义的某个接口的变量可以存储同样实现该接口的任意类型对象 ,即是说任意类型,只要实现了 Reader 和 Closer 即可以用来解析resp.Body。

那我们来验证一下示例里面使用的三种方法是不是符合我们这个结论。

验证

  • strings.NewReader

    我们可以在C:\Go\src\strings\reader.go看到 Reader 类型的 Read方法:

  • bytes.NewBuffer

    我们可以在C:\Go\src\bytes\buffer.go看到 Buffer 类型的 Read方法:

  • ioutil.ReadAll

    我们可以在C:\Go\src\io\ioutil\ioutil.go看到 io.Reader 类型的 ReadAll和Close() error方法:

发送Json/XMl

在了解了上面的知识之后,我们再来看发送Json、XML数据等就比较简单了。

Json请求示例代码

python 复制代码
func JsonReq() {
	info := make(map[string]interface{})
	info["name"] = "Detector"
	info["age"] = 15
	info["loc"] = "深圳"
	// 将map解析未[]byte类型
	bytesData, _ := json.Marshal(info)
	// 将解析之后的数据转为*Reader类型
	reader := bytes.NewReader(bytesData)
	println(reader)
	resp, _ := http.Post("http://httpbin.org/post",
		"application/json",
		reader)
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}

代码里面给了一些注释,我们把要发送的数据转化为了 *Reader类型,然后就可以直接发送了。(我们从上面的源码分析可以知道这个类型是可以存储io.Reader的数据的)

xml请求示例代码

python 复制代码
func XMLReq() {
	xml := `<?xml version="1.0" encoding="UTF-8"?>
	<resources>
		<string name="VideoLoading">Loading video...</string>
		<string name="ApplicationName">what</string>
	</resources>`
	bytesData := strings.NewReader(xml)
	resp, _ := http.Post("http://httpbin.org/post",
		"application/xml",
		bytesData)
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}

总结

  • Json、xml请求
  • 请求、响应数据简析
  • interface概念复习

资料获取方法

【留言777】

各位想获取源码等教程资料的朋友请 点赞 + 评论 + 收藏 ,三连!

三连之后我会在评论区挨个私信发给你们~

相关推荐
学Linux的语莫1 小时前
python中类的常见写法
开发语言·python·状态模式
重生之高冷汉堡包2 小时前
ChatGPT 如何打造自动化账号:从零搭建到高效运营
运维·chatgpt·自动化
郝学胜-神的一滴2 小时前
游戏设计:原型与开发 08:我们到底在为谁做游戏
程序人生·游戏·游戏引擎·游戏开发·游戏策划
垆边人似月.2 小时前
Python中如何使用get函数实现频次查询
服务器·前端·python
AI 编程助手GPT2 小时前
GPT 脚本别只发一个文件:用 uv 把依赖和锁一起交付
人工智能·python·gpt·uv·依赖管理
Patrick在香港3 小时前
第 16,216 次连接之后,它不干了
python·网络编程·socket·tcp·连接池
我命由我123453 小时前
Python 开发 - Python 虚拟环境
运维·开发语言·后端·python·http·https·java-ee
软件派3 小时前
Beam.Win 自动化办公与业务流程提效指南
运维·自动化
云和数据.ChenGuang3 小时前
LLM大模型对接本地Ollama部署模型
开发语言·人工智能·python·langchain
星禾元亨3 小时前
用结构化数据与干净实体信号,让技术内容被 AI 搜索引擎稳定引用
数据库·人工智能·自动化·创业创新