阅读 2319

golang造轮子,封装一个简单的http client | 🏆 技术专题第二期征文

近来无事,本着爱折腾的原则,在go原生 http client 的基础上,自己封装了一个go的http client。由于才疏学浅,再加是第一次造轮子,在各位大佬面前献丑了,写的烂的地方,请轻喷。还请各位不吝赐教。

先放地址

gethub: github.com/bruce12397/…

Gitee: gitee.com/bruce_le/ea…

简单介绍一下功能

  1. 使用 构造器模式,提供了链式调用和方便使用的接口
  2. 支持https自定义服务器证书校验和双向证书校验
  3. 支持代理,可以方便的设置代理
  4. 封装了multipart 协议, 可以方便的上传文件
  5. 具有很强的拓展性,可以在基础上非常方便的定制自己http请求
  6. 支持http的 返回结果 异步回调
  7. 可以方便的自定义Response

安装库

可以使用github的库,也可使用Gitee的库,两个库的代码都是一样的,因为github网速的原因,所以在gitee上也传了一份

  1. github:go get -u github.com/bruce12397/easy_http

  2. gitee: go get -u gitee.com/bruce_le/easy_http

使用

引入库

因为github和gitee拉下来的库目录不同,所以以github的为准

import "github.com/bruce12397/easy_http"
复制代码

具体使用

全部配置
func main() {
	//得到一个http client的构造器
	builder := easy_http.NewClientBuilder()

	//是否跳过服务器证书校验
	builder.SkipVerify(false)

	//设置超时时间
	builder.TimeOut(time.Second * 5)

	//设置代理
	builder.ProxyUrl("http://127.0.0.1:10809")

	//设置根证书
	var certPool [1]string
	certPool[0] = "D:\\server.pem"
	builder.Cert(certPool[:])
	
	//设置双向校验证书
	var tlsPath [1]*easy_http.TlsPath
	tlsPath[0] = &easy_http.TlsPath{
		CertFile: "D:\\client.pem",
		KeyFile:  "D:\\client.key",
	}
	builder.Tls(tlsPath[:])

	//设置http请求header
	header := make(map[string]string)
	header["Accept-Language"] = "Accept-Language: en,zh"
	builder.Header(header)

	//设置http请求cookie
	cookie := make(map[string]string)
	cookie["name"] = "value"
	builder.Cookie(easy_http.EasyCookie(cookie))

	//开启cookie jar
	builder.Jar(nil)

	//设置 Response 处理函数
	builder.BuildResponse(easy_http.EasyBuildResponse)

	//构造client
	client, err := builder.Build()
	if err != nil {
		fmt.Println("aa", err)
		return
	}
}
复制代码

这样就初始化一个http的客户端

当然,上面的例子是设置了所有配置的,也可以全部使用默认配置

使用默认配置
func DefaultClient() {
	builder := easy_http.NewClientBuilder()
	client, err := builder.Build()
	if err != nil {
		fmt.Println(err)
		return
	}
	client.Get("http://baidu.com")
}
复制代码

这样同样是可以的

easy 函数 使用

库中提供了一些函数,可以方便的构造http请求相关的结构

func EasyFunction() {

	url := "http://baidu.com"

	//合成http get的url和参数 
	values := make(map[string]string)
	values["v"] = "123456"
	easy_http.EasyGet(url, values)

	//构造cookie
	cookie := make(map[string]string)
	cookie["name"] = "value"
	easy_http.EasyCookie(cookie)

	//合成 http post 的参数
	easy_http.EasyPost(values)

	//构造 上传文件的multipart
	multipartBuilder := easy_http.NewMultipartBuilder()
	multipartBuilder.AddFile("file1","D:\\a.txt")
	multipartBuilder.AddFromDate("name","value")
	multipartBuilder.AddBytes("name2",[]byte("aaaaa"))
	multipart, err := multipartBuilder.Builder()
	
}
复制代码
异步回调使用

库封装了 异步回调功能,请求会在一个新的goroutine中进行。当http请求完成时,会回调函数。回调函数可用形参使用传入函数和实现接口两种方式


func Call(response easy_http.IResponse) {
	fmt.Println(response.Error())
	fmt.Println(response.StatusCode())
	fmt.Println(string(response.Content()))
}

type Get struct {
}

func (g Get) EasyResponseCallback(response easy_http.IResponse) {
	fmt.Println(response.Error())
	fmt.Println(response.StatusCode())
	fmt.Println(string(response.Content()))
}

func AsynchronousRequest() {
	url := "http://baidu.com"
	client, err := easy_http.NewClientBuilder().Build()
	if err != nil {
		fmt.Println(err)
		return
	}

	//函数异步回调
	client.GetAsyn(url, Call)

	//接口异步回调
	client.GetAsynWithCallback(url, &Get{})
}
复制代码
自定义请求

因为库中只封装了 GET和POST这两种方式,向PUT,DELETE等这些方式需要自己去实现。所以,可以使用下面的函数来实现

func Call(response easy_http.IResponse) {
	fmt.Println(response.Error())
	fmt.Println(response.StatusCode())
	fmt.Println(string(response.Content()))
}

func CustomizeRequest() {
	url := "http://baidu.com"
	client, err := easy_http.NewClientBuilder().Build()
	if err != nil {
		fmt.Println(err)
		return
	}
	response := client.SendWithMethod(url, http.MethodPut, nil, func(request *http.Request) {
		//修改Request
	})
	fmt.Println(response.Error())
	fmt.Println(response.StatusCode())

	//异步方式
	client.SendWithMethodCallBack(url, http.MethodPut, nil, func(request *http.Request) {
		//习惯Request
	}, Call)
}
复制代码
使用go http默认的函数请求

当需要有一些特殊的请求,这个库无法满足时,可以使用go http原生的方式来请求

func Primitive() {
	url := "http://baidu.com"
	client, err := easy_http.NewClientBuilder().Build()
	if err != nil {
		fmt.Println(err)
		return
	}
	//获取Request
	request, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	//得到http的原生Response
	response, err := client.DoRequest(request)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(response)
}
复制代码
自定义Response

库中返回的Response是一个接口类型,只要实现了这个接口,都可作为返回值返回,自定义的Response,在构造client的设置就可以了

type MyResponse struct {
}

func (m MyResponse) Error() error {
	return nil
}

func (m MyResponse) StatusCode() int {
	return 0
}

func (m MyResponse) Header() http.Header {
	return nil
}

func (m MyResponse) ContentLength() int64 {
	return 0
}

func (m MyResponse) Content() []byte {
	return nil
}

func (m MyResponse) Resp() *http.Response {
	return nil
}

func (m MyResponse) Request() *http.Request {
	return nil
}

func (m MyResponse) Cookie(name string) *http.Cookie {
	return nil
}

//构造HTTP response的函数
func MyBuildResponse(resp *http.Response, err error) easy_http.IResponse {
	response := new(MyResponse)
    //做处理
	return response
}
func CustomizeResponse() {
	client, err := easy_http.NewClientBuilder().
		BuildResponse(MyBuildResponse).
		Build()
	if err != nil {
		fmt.Println(err)
		return
	}
}
复制代码

结构体 MyResponse 实现了 easy_http.IResponse 这个接口。然后在MyBuildResponse这个函数中,new 一个 MyResponse的对象,再根据自己的需要,做相应的处理就可以了。
clientBuilder.BuildResponse(MyBuildResponse)设置就可以了

最后

整个库的基本功能就是这些了。第一造轮子,写的很烂。写这篇文章时,还发现了好几个因为首字母小写导致的问题。

有问题的地方,还请不吝赐教

文章分类
后端
文章标签