写在前面

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

发送Post请求

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

示例代码

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请求的源码:

func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}
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中:

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中我们可以看到对应的定义是这样的:

type ReadCloser interface {
Reader
Closer
}

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

type Closer interface {
Close() error
}

根据我们上面的结论-- 定义的某个接口的变量可以存储同样实现该接口的任意类型对象,即是说任意类型,只要实现了 ReaderCloser 即可以用来解析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类型的 ReadAllClose() error方法:

发送Json/XMl

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

Json请求示例代码

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请求示例代码

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概念复习

【Golang 接口自动化02】使用标准库net/http发送Post请求的更多相关文章

  1. 【Golang 接口自动化01】使用标准库net/http发送Get请求

    发送Get请求 使用Golang发送get请求很容易,我们还是使用http://httpbin.org作为服务端来进行演示. package main import ( "bytes&quo ...

  2. 【Golang 接口自动化06】微信支付md5签名计算及其优化

    前言 可能看过我博客的朋友知道我主要是做的支付这一块的测试工作.而我们都知道现在比较流行的支付方式就是微信支付和支付宝支付,当然最近在使用低手续费大力推广的京东金融(已改名为京东数科)以后也可能站到第 ...

  3. 【Golang 接口自动化00】为什么要用Golang做自动化?

    为什么使用Golang做自动化 顺应公司的趋势学习了Golang之后,因为没有开发那么多的时间和项目来实践,怕步此前学习Java缺少练习遗忘殆尽的后尘,决定利用工作之余的时间把此前用Python的写的 ...

  4. 【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试

    前言 Mock是一个做自动化测试永远绕不过去的话题.本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法. 可能有的小伙伴不太了解mock在实际自动化测试过程中 ...

  5. 【Golang 接口自动化04】 解析接口返回JSON串

    前言 上一次我们一起学习了如何解析接口返回的XML数据,这一次我们一起来学习JSON的解析方法. JSON(Javascript Object Notation)是一种轻量级的数据交换语言,以文字为基 ...

  6. 【python接口自动化】- 使用requests库发送http请求

    前言:什么是Requests ?Requests 是⽤Python语⾔编写,基于urllib,采⽤Apache2 Licensed开源协议的 HTTP 库.它⽐ urllib 更加⽅便,可以节约我们⼤ ...

  7. 【Golang 接口自动化05】使用yml管理自动化用例

    我们在前面几篇文章中学习怎么发送数据请求,怎么处理解析接口返回的结果,接下来我们一起来学习怎么进行测试用例管理,今天我们介绍的是使用yml文件进行用例管理,所以首先我们一起来了解一下YAML和它的简单 ...

  8. 【Golang 接口自动化03】 解析接口返回XML

    上一篇我们学习了怎么发送各种数据类型的http请求,这一篇我们来介绍怎么来解析接口返回的XML的数据. 解析接口返回数据 定义结构体 假设我们现在有一个接口返回的数据resp如下: <?xml ...

  9. 【Golang 接口自动化07】struct转map的三种方式

    背景 我们在前面介绍过怎么使用net/http发送json或者map数据,那么它能不能直接发送结构体数据呢?我们今天一起来学习结构体struct转map的三种方法,为后续做铺垫. struct转map ...

随机推荐

  1. html09

    1.Jquery的常用方法1)选择器2)操作节点以下的 obj 都是指 jQuery对象 1.操作样式 obj.css() :不加参数是获取节点的css样式 obj.css({"属性&quo ...

  2. VS2010/MFC编程入门之五十三(Ribbon界面开发:为Ribbon Bar添加控件)

    前面一节中鸡啄米为大家简单介绍了如何创建Ribbon样式的应用程序框架,本节教程就来初步讲讲怎样为Ribbon Bar添加Ribbon控件. VS2010为Ribbon界面开发提供了Ribbon De ...

  3. VS2010/MFC编程入门之四十六(MFC常用类:MFC异常处理)

    上一节中鸡啄米讲了CFile文件操作类,本节主要来说说MFC异常处理. 在鸡啄米C++编程入门系列的最后一节鸡啄米:C++编程入门系列之五十(异常处理)中,鸡啄米讲了C++标准异常的处理机制,如果你还 ...

  4. nginx之rewrite重写,反向代理,负载均衡

    rewrite重写(伪静态): 在地址栏输入xx.com/user-xxx.html, 实际上访问的就是xxx.com/user.php?id=xxx rewrite就这么简单 附上ecshop re ...

  5. Learning to Rank算法介绍:RankSVM 和 IR SVM

    之前的博客:http://www.cnblogs.com/bentuwuying/p/6681943.html中简单介绍了Learning to Rank的基本原理,也讲到了Learning to R ...

  6. mysql事务(二)——控制语句使用

    事务控制 一般来说,mysql默认开启了事务自动提交功能,每条sql执行都会提交事务.可以使用如下语句关闭事务自动提交功能. show session variables like 'autocomm ...

  7. MySQL数据库----单表查询

    先创建表 #创建表 create table employee( id int not null unique auto_increment, name varchar(20) not null, s ...

  8. Linux下Oracle常用命令

    1. 备份表 exp database_user/pass tables='(table1,table2)' file=filename.dmp(例如:exp ismrenbao/iflytek ta ...

  9. (三)github之GIT的导入

    什么是版本管理? git是一款[分散型版本管理]软件,提供了开发过程中不可少的功能,例如记录一款软件添加或者更改源代码的过程,回溯到特定阶段,恢复误删除的文件等. 集中型:将仓库集中放在服务器中,一旦 ...

  10. Python面试题之装饰器漫谈

    讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它 ...