Golang的一个简单实用的http客户端库httpc

httpc简介

httpc这是一个发起http请求的客户端库。
它具有的特色包括:简单易用、易于扩展、支持链式调用、支持多种格式的处理等。
特别适合用来调用restfull风格的接口。

项目地址

https://coding.net/u/recallsong/p/httpc/git

下载

go get git.coding.net/recallsong/httpc.git

Api文档

查看Api文档

我们也可以利用godoc工具在本地查看api文档:

godoc -http=:9090

在浏览器中查看地址:
http://localhost:9090/pkg/coding.net/recallsong/httpc

快速入门

最简单的使用方式

var resp string
// GET http://localhost/hello?name=RecallSong
err := httpc.New("http://localhost").Path("hello").Query("name", "RecallSong").Get(&resp)
if err != nil {
    fmt.Println(resp) // 以字符串方式获取响应的数据
} else {
    fmt.Println(err)
}

设置请求头和Cookie等

var resp string
err := httpc.New("http://localhost").Path("/hello").Query("param", "value").
    Header("MyHeader", "HeaderValue").
    AddCookie(&http.Cookie{Name: "cookieName", Value: "cookieValue"}).
    Body("body data").Post(&resp)
if err != nil {
    fmt.Println(resp) // 以字符串方式获取响应的数据
} else {
    fmt.Println(err)
}

发送和接收json格式的数据

使用map传递数据

body := map[string]interface{}{
    "name": "RecallSong",
    "age":  18,
}
var resp map[string]interface{}
// 根据请求的Content-Type自动对数据进行转换
err := httpc.New("http://localhost").Path("json").
    ContentType(httpc.TypeApplicationJson).
    Body(body). // body转变为 {"name":"RecallSong","age":18}
    Post(&resp) // 根据响应中的Content-Type,将返回的数据解析到resp中
fmt.Println(err, resp)

// 如果请求或响应没有指定Content-Type,或是不正确,也可以强制指定转换格式类型
err = httpc.New("http://localhost").Path("json").
    Body(body, httpc.TypeApplicationJson). // body转变为 {"name":"RecallSong","age":18}
    Post(&resp, httpc.TypeApplicationJson) // 将返回的数据按json格式解析到map中
fmt.Println(err, resp)

使用struct传递数据

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}
body := Person{Name: "RecallSong", Age: 18}
var resp Person
err := httpc.New("http://localhost").Path("json").
    Body(body, httpc.TypeApplicationJson).
    Post(&resp, httpc.TypeApplicationJson)
fmt.Println(err, resp)

发送和接收xml格式的数据

type Person struct {
    Name string `xml:"name"`
    Age  int    `xml:"age"`
}
body := Person{Name: "RecallSong", Age: 18}
var resp Person
err := httpc.New("http://localhost").Path("xml").
    Body(body, httpc.TypeApplicationXml). // 数据转变为xml格式
    Post(&resp, httpc.TypeApplicationXml)
fmt.Println(err, resp)

发送表单参数

使用结构体发送

sbody := struct {
    Name string `form:"name"`
    Age  int    `form:"age"`
}{
    Name: "RecallSong",
    Age:  18,
}
var resp string
err := httpc.New("http://localhost").Path("echo").
    Body(sbody, httpc.TypeApplicationForm). // 将结构体转变为form格式的数据体
    Post(&resp)
fmt.Println(err, resp)

使用map发送

mbody := map[string]interface{}{
    "name": "RecallSong",
    "age":  19,
}
var resp string
err := httpc.New("http://localhost").Path("echo").
    Body(mbody, httpc.TypeApplicationForm). // 将map变为form格式的数据体
    Post(&resp)
fmt.Println(err, resp)

使用url.Values发送

ubody := url.Values{}
ubody.Set("name", "RecallSong")
ubody.Set("age", "20")
var resp string
err := httpc.New("http://localhost").Path("echo").
    Body(ubody). // 将url.Values类型转变form格式的数据体
    Post(&resp)
fmt.Println(err, resp)

自动编码url路径参数

var resp string
// 可以自动编码url路径参数
err := httpc.New("http://localhost").EscapedPath("recall/Song").EscapedPath(18).Get(&resp)
// 请求地址为 http://localhost/recall%2FSong/18
fmt.Println(err, resp)

上传文件

方式1

file, err := os.Open("doc.go")
if err != nil {
  fmt.Println(err)
  return
}
defer file.Close()
body := map[string]interface{}{
    "file":  file,
    "name":  "RecallSong",
    "age":   18,
    "file2": httpc.FilePath("doc.go:hello.go"), //上传doc.go文件,参数名为file2,文件名为hello.go
}
var resp string
err = httpc.New("http://localhost").Path("echo").
    Body(body, httpc.TypeMultipartFormData).Post(&resp)
fmt.Println(err)

方式2

file, err := os.Open("doc.go")
if err != nil {
    fmt.Println(err)
    return
}
defer file.Close()
body := struct {
    Name    string         `form:"name"`
    Address []string       `form:"address"`
    Age     int            `form:"age"`
    File    *os.File       `form:"file" file:"hello.go"`
    File2   httpc.FilePath `form:"file2"`
}{
    Name:    "RecallSong",
    Address: []string{"HangZhou", "WenZhou"},
    Age:     18,
    File:    file,
    File2:   httpc.FilePath("doc.go:hello2.go"), //上传doc.go文件,参数名为file2,文件名为hello2.go
}
var resp string
err = httpc.New("http://localhost").Path("echo").
    Body(body, httpc.TypeMultipartFormData).Post(&resp)
fmt.Println(err)

接收响应数据

// 前面的例子我们知道了可以接收json和xml格式的数据,也可以接收数据到一个string变量中
// 除此之外,我们还可以有一下几种方式接收数据

// []byte 方式接收
var bytesResp []byte
err := httpc.New("http://localhost").Path("hello").Get(&bytesResp)
fmt.Println(err, bytesResp)

// *http.Response 方式接收
var resp *http.Response
err := httpc.New("http://localhost").Path("hello").Get(&resp)
if err != nil {
  fmt.Println(err)
} else {
  // 注意这种方式要关闭Body
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  fmt.Println(err, string(body))
}

下载文件

方式1

// 默认方式保存文件
err := httpc.New("http://localhost").Path("echo").Body("content").Post(httpc.FilePath("download1.txt"))
fmt.Println(err)

方式2

err := httpc.New("http://localhost").Path("echo").Body("content").Post(&httpc.SaveInfo{
    Path:     "download2.txt",
    Override: true,
    Mode:     0777})
fmt.Println(err)

指定成功的http状态码

// 如果返回的状态码与指定的状态码不匹配,则返回一个error
err := httpc.New("http://localhost").Path("not_exist").
    SuccessStatus(200).Get(nil)
fmt.Println(err)
// Output:
// error http status 404 , expect 200

请求上下文

// 请求上下文中包含了每次请求的设置、连接设置等,所有请求应该尽量共享Context
// 我们可以设置回调通知的函数
ctx := httpc.NewContext().
AddCbBeforeSend(func(client *httpc.HttpC, args ...interface{}) error {
    fmt.Println("before request")
    return nil
}).
AddCbAfterSend(func(client *httpc.HttpC, args ...interface{}) error {
    fmt.Println("after response")
    return nil
}).
AddCbOnError(func(client *httpc.HttpC, args ...interface{}) error {
    fmt.Println("on error")
    return nil
}).
SetConnectReadTimeout(30*time.Second, 30*time.Second)
var resp string
err := httpc.New("http://localhost").Path("hello").SetContext(ctx).Get(&resp)
fmt.Println(err, resp)

// 库默认生成了一个上下文实例 httpc.DefaultContext,它并没有加锁保护,所以尽量在所有请求前设置好它
// 改变httpc.DefaultContext会影响所有未调用过SetContext的请求
httpc.DefaultContext.SetConnectReadTimeout(30*time.Second, 30*time.Second)
err = httpc.New("http://localhost").Path("hello").Get(&resp)
fmt.Println(err, resp)

超时设置

err := httpc.New("http://localhost").Path("timeout").
SetContext(httpc.NewContext().SetConnectReadTimeout(time.Second, time.Second)).
  Get(nil)
fmt.Println(err)

请求重试

err := httpc.New("http://not_exist/").Path("not_exist").
    SetContext(httpc.NewContext().AddCbOnRetring(func(c *httpc.HttpC, args ...interface{}) error {
        fmt.Printf("retring %v, next interval %v\n", args[0], args[1])
        return nil
    }).SetRetryConfig(3, time.Second, 2)). // 重试3次,重试时间间隔依次为:2s, 4s, 8s
    Get(nil)
fmt.Println(err)

// Output:
// retring 1, next interval 2s
// retring 2, next interval 4s
// retring 3, next interval 8s
// Get http://not_exist/not_exist: dial tcp: lookup not_exist: no such host

自定义请求或响应处理器

// httpc库已经注册了一些通用的请求和响应处理器,但我们也可以额外添加处理器
ctx := httpc.NewContext()
ctx.BodyReaders = httpc.NewBodyReaders()
ctx.BodyReaders.RespBodyTypeReaders[reflect.TypeOf((*int)(nil))] = func(resp *http.Response, reader io.ReadCloser, typ reflect.Type, out interface{}) error {
    output := out.(*int)
    *output = resp.StatusCode
    return nil
}
// 返回响应状态码
var status int
err := httpc.New("http://localhost").Path("hello").
    SetContext(ctx).
    Get(&status)
fmt.Println(err, status)
// Output:
// <nil> 200

其他特性

请参考Api文档或源码

原文地址:http://blog.51cto.com/13599072/2072948

时间: 2024-07-31 06:49:47

Golang的一个简单实用的http客户端库httpc的相关文章

开发一个简单实用的android紧急求助软件

之前女朋友一个人住,不怎么放心,想找一个紧急求助的软件,万一有什么突发情况,可以立即知道.用金山手机卫士的手机定位功能可以知道对方的位置状态,但不能主动发送求助信息,在网上了很多的APK,都是鸡肋功能,都需要解锁.并打开软件,真正的紧急情况可能没有时间来完成这一系列操作. 于是我自己做了一个这样的软件,在紧急情况下,连续按电源键5次即可发送求救短信和位置信息给事先指定的用户,这个操作在裤兜里就能完成.原理很简单,就是设置监听器捕获屏幕的开关,在较短的时间内屏幕开关达到一定次数后,触发手机定位,定

nodejs + jquery Mobile构建一个简单的移动web (客户端)

前面展示了使用nodejs技术和jqm来搭建一个简单的支持CRUD操作应用的服务端部分(参见:nodejs + jquery Mobile构建一个简单的移动web(服务端) ),服务端采用nodejs技术实现,使用了mongodb数据库和轻量级web开发框架expressJS, 路由使用restful风格,所以你也可以使用restify来开发. 客户端的实现主要通过ajax调用实现.使用jade模板引擎. 客户端主要包含两个文件:layout.jade和index.jade 1. layout.

LogCook 一个简单实用的Android日志管理工具

众所周知,日志的管理是软件系统很重要的一部分,千万不可忽略其重要性.完整的日志将会在系统维护中起着异常重要的作用,就好像磨刀不误砍柴工一样,日志就像对系统进行分析的工具,工具便捷了,对系统分析起来就能达到事半功倍的效果.开发者必须要明白日志的价值和意义,万万不可忽略和轻视. LogCook是一款非常简洁实用的Android日记管理工具.LogCook的中文翻译是日志厨师,你可以把它看作是一个日志美食家. 特点 作为一款日志管理工具它最大的特点就是简单实用,与Android原生的日志功能相比较它具

一个简单实用的log类

自己写一些小代码的时候总是用fprintf来写log,感觉这样不太科学,还是写一个通用的简单带log level的log类,以后就拿来复用吧.这个类实现了非常简单的功能:如果指定了log文件path和name创建一个log文件,并将各种level的写入文件中,否则都打印到屏幕,格式如下: [DEBUG] : xxxxx [WARN] : xxxx [MSG] : xxxxx 代码: //--------------log.h---------------------- #ifndef __LOG

Python网络编程——编写一个简单的回显客户端/服务器应用

今天将python中socket模块的基本API学习完后,照着书上的实例编写一个套接字服务器和客户端.采用python3.5版本,在注释中会标明python2和python3的不同之处. 1.代码 (1)服务器端及对应代码解释 1 # ! /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # 编写回显服务器 4 5 import socket 6 import sys 7 import argparse 8 9 # 定义常量 10 host = 'l

用C++写一个简单的服务器和客户端

我们将创建一个服务器节点add_two_ints_server,它将会收到两个整数,并且返回它们的和.切换目录到之前建立的beginner_tutorials包下: cd ~/catkin_ws/src/beginner_tutorials 编辑src/add_two_ints_server.cpp文件: vim src/add_two_ints_server.cpp 也就是说我们写的客户点也是一个node节点,它的cpp和生成的可执行模块和前面的talker.listener是一样的,只不过他

中级JavaScript例子, 如何实现一个简单实用的模板套用机制, GXTemplate , 第一章(估计要写9章)

我们是刚刚成立的, 一家传统的软件开发公司(只有几个人的小公司), 主营业务就是传统行业软件项目的外包. 由于这种项目需要的技术不深, 但是对开发效率有很高的要求, 所以我们在慢慢的摸索一下快速开发模式. 同时也愿意把其中不杂乱的部分,分享出来. 这一系列的文章主要是针对GXTemplate, 一个模板套用类库 (谈不上框架) 这并不是一个 "如何使用" 的教程 , 而是一个 "如何创造" 这种类库的教程. 特点是, 我们会把整个创造过程, 由v0.1的原始版本开始

Python 使用Socket模块编写一个简单的服务器和客户端

任务 Socket套接字开始监听后,使用accept函数来等待客户连接.这个过程在循环中无限循环,服务器处理完和客户端的连接后会再次调用accpet函数,等待下一个连接. 客户端代码 1 import socket 2 s1=socket.socket() 3 s1.bind(("127.0.0.1",2345)) 4 s1.listen(5) 5 while 1: 6 conn,address = s1.accept() 7 print("a new connect fro

一个简单实用的css loading图标

摘要 在web开发中,为了提高用户体验,在加载数据的时候都会给一个loading的提示. Html <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>&