Documentation
¶
Overview ¶
Author: recallsong
Email: songruiguo@qq.com
Description: httpc是一个简单的发起http请求的客户端库
Index ¶
- Constants
- Variables
- type BodyReaders
- type Callback
- type Context
- func (c *Context) AddCbAfterSend(cb Callback) *Context
- func (c *Context) AddCbBeforeSend(cb Callback) *Context
- func (c *Context) AddCbOnError(cb Callback) *Context
- func (c *Context) AddCbOnRetring(cb Callback) *Context
- func (c *Context) EnableCookie(enable bool) *Context
- func (c *Context) SetCheckRedirect(cr func(req *http.Request, via []*http.Request) error) *Context
- func (c *Context) SetClient(client *http.Client) *Context
- func (c *Context) SetConnectReadTimeout(connectTimeout time.Duration, readTimeout time.Duration) *Context
- func (c *Context) SetProxy(proxy func(*http.Request) (*url.URL, error)) *Context
- func (c *Context) SetRetryConfig(retries int, interval time.Duration, factor float64) *Context
- func (c *Context) SetTLSClientConfig(config *tls.Config) *Context
- func (c *Context) SetTotalTimeout(timeout time.Duration) *Context
- type FilePath
- type HttpC
- func (c *HttpC) AddCookie(ck *http.Cookie) *HttpC
- func (c *HttpC) AddHeader(key, value string) *HttpC
- func (c *HttpC) BasicAuth(userName, password string) *HttpC
- func (c *HttpC) Body(body interface{}, mediaType ...string) *HttpC
- func (c *HttpC) ContentType(value string) *HttpC
- func (c *HttpC) Delete(out interface{}, mediaType ...string) error
- func (c *HttpC) DumpRequest(dumpBody ...bool) string
- func (c *HttpC) DumpResponse(dumpBody ...bool) string
- func (c *HttpC) EscapedPath(path interface{}) *HttpC
- func (c *HttpC) Get(out interface{}, mediaType ...string) error
- func (c *HttpC) Header(key, value string) *HttpC
- func (c *HttpC) Options(out interface{}, mediaType ...string) error
- func (c *HttpC) Patch(out interface{}, mediaType ...string) error
- func (c *HttpC) Path(path string) *HttpC
- func (c *HttpC) Post(out interface{}, mediaType ...string) error
- func (c *HttpC) Put(out interface{}, mediaType ...string) error
- func (c *HttpC) Query(name, value string) *HttpC
- func (c *HttpC) Reset() *HttpC
- func (c *HttpC) SetContext(context *Context) *HttpC
- func (c *HttpC) String() string
- func (c *HttpC) SuccessStatus(sucStatus int) *HttpC
- type ReqBodyReader
- type RespBodyReader
- type SaveInfo
Examples ¶
Constants ¶
const ( POST = "POST" GET = "GET" HEAD = "HEAD" PUT = "PUT" DELETE = "DELETE" PATCH = "PATCH" OPTIONS = "OPTIONS" )
支持的HTTP method
const ( TypeTextHtml = "text/html" TypeTextPlain = "text/plain" TypeApplicationJson = "application/json" TypeApplicationXml = "application/xml" TypeApplicationForm = "application/x-www-form-urlencoded" TypeApplicationStream = "application/octet-stream" TypeMultipartFormData = "multipart/form-data" )
支持的ContentType类型
Variables ¶
var DefaultContext = NewContext()
var (
ErrReqBodyType = errors.New("invalid request body type")
)
var (
ErrRespOutType = errors.New("invalid response output type")
)
var GlobalReqBodyMediaReaders = map[string]ReqBodyReader{
TypeApplicationJson: jsonReqBodyReader,
TypeApplicationXml: xmlReqBodyReader,
TypeApplicationForm: formValuesReqBodyReader,
TypeMultipartFormData: multipartReqBodyReader,
}
GlobalReqBodyMediaReaders 默认的根据MediaType获取RequestBody的Reader映射
var GlobalReqBodyTypeReaders = map[reflect.Type]ReqBodyReader{ reflect.TypeOf(""): stringReqBodyReader, reflect.TypeOf([]byte(nil)): bytesReqBodyReader, reflect.TypeOf(url.Values(nil)): urlValuesReqBodyReader, }
GlobalReqBodyTypeReaders 默认的根据类型获取RequestBody的Reader映射
var GlobalRespBodyMediaReaders = map[string]RespBodyReader{
TypeApplicationJson: readAllRespWrapper(jsonRespBodyReader),
TypeApplicationXml: readAllRespWrapper(xmlRespBodyReader),
TypeApplicationStream: streamRespBodyReader,
}
GlobalRespBodyMediaReaders 默认的根据MediaType获取ResponseBody的Reader映射
var GlobalRespBodyTypeReaders = map[reflect.Type]RespBodyReader{ reflect.TypeOf((*string)(nil)): readAllRespWrapper(stringRespBodyReader), reflect.TypeOf((*[]byte)(nil)): readAllRespWrapper(bytesRespBodyReader), reflect.TypeOf((**http.Response)(nil)): responseReader, reflect.TypeOf((FilePath)("")): downloadRespBodyReader, reflect.TypeOf((*SaveInfo)(nil)): downloadRespBodyReader, reflect.TypeOf(SaveInfo{}): downloadRespBodyReader, }
GlobalRespBodyTypeReaders 默认的根据类型获取ResponseBody的Reader映射
Functions ¶
This section is empty.
Types ¶
type BodyReaders ¶
type BodyReaders struct {
ReqBodyTypeReaders map[reflect.Type]ReqBodyReader // 根据类型获取reader
ReqBodyMediaReaders map[string]ReqBodyReader // 根据MediaType获取reader
RespBodyTypeReaders map[reflect.Type]RespBodyReader // 根据类型获取reader
RespBodyMediaReaders map[string]RespBodyReader // 根据MediaType获取reader
}
BodyReaders
type Context ¶
type Context struct {
Client *http.Client // 请求的客户端
BodyReaders *BodyReaders // 获取请求和响应中的body的reader
CbBeforeSend []Callback // 在发送请求前调用
CbAfterSend []Callback // 在发送请求后调用
CbOnError []Callback // 在发生错误时调用
CbOnRetring []Callback // 在请求重试时调用
Retries int // 重试次数,-1表示一直重试
RetryInterval time.Duration // 重试间隔
RetryFactor float64 // 重试因子,影响每次重试的时间间隔
}
Context http请求上下文,管理所有请求公用的对象
func (*Context) AddCbAfterSend ¶
AddCbAfterSend 添加发送请求后的通知回调函数
func (*Context) AddCbBeforeSend ¶
AddCbBeforeSend 添加发送请求前的通知回调函数
func (*Context) AddCbOnError ¶
AddCbOnError 添加发生错误时的通知回调函数
func (*Context) AddCbOnRetring ¶
AddCbOnRetring 添加请求重试的通知回调函数
func (*Context) EnableCookie ¶
EnableCookie 启用CookieJar
func (*Context) SetCheckRedirect ¶
SetCheckRedirect 设置CheckRedirect
func (*Context) SetConnectReadTimeout ¶
func (c *Context) SetConnectReadTimeout(connectTimeout time.Duration, readTimeout time.Duration) *Context
SetConnectReadTimeout 设置请求的连接超时和读数据超时
func (*Context) SetRetryConfig ¶
SetRetryConfig 设置重试的配置
func (*Context) SetTLSClientConfig ¶
SetTLSClientConfig 设置TLSClientConfig
type HttpC ¶
type HttpC struct {
Context *Context // 上下文
Request *http.Request // 请求
Response *http.Response // 响应
BaseURL string // 请求url基地址
URL string // 请求的url
QueryData url.Values // 请求url的query参数
SendMediaType string // 请求的ContentType
Data interface{} // 要发送的数据体
Error error // 请求发生的错误
SucStatus int // 指定成功的状态码,不匹配则以Error的形式返回
}
HttpC 发起http请求的Client
Example (Body_reader) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"reflect"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
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(baseUrl).Path("hello").
SetContext(ctx).
Get(&status)
fmt.Println(err, status)
}
Output: <nil> 200
Example (Context) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
ctx := httpc.NewContext().
AddCbBeforeSend(func(client *httpc.HttpC, args ...interface{}) error {
// fmt.Println(client.DumpRequest())
fmt.Println("before request")
return nil
}).
AddCbAfterSend(func(client *httpc.HttpC, args ...interface{}) error {
// fmt.Println(client.DumpResponse())
fmt.Println("after response")
return nil
}).
AddCbOnError(func(client *httpc.HttpC, args ...interface{}) error {
// fmt.Println(client.Error)
fmt.Println("on error")
return nil
}).
SetConnectReadTimeout(30*time.Second, 30*time.Second)
var resp string
err := httpc.New(baseUrl).Path("hello").Query("name", "Song").SetContext(ctx).SuccessStatus(200).Get(&resp)
fmt.Println(err, resp)
}
Output: before request after response <nil> Hello, Song
Example (Download) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
// 默认方式保存文件
err := httpc.New(baseUrl).Body("xxx").Path("echo").Post(httpc.FilePath("download1.txt"))
fmt.Println(err)
_, err = os.Stat("download1.txt")
if os.IsNotExist(err) {
fmt.Println(err)
}
// 保存文件的另一种方式
err = httpc.New(baseUrl).Body("zzz").Path("echo").Post(&httpc.SaveInfo{
Path: "download2.txt",
Override: true,
Mode: 0777})
fmt.Println(err)
_, err = os.Stat("download2.txt")
if os.IsNotExist(err) {
fmt.Println(err)
}
}
Example (Dump) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
var resp []byte
// 构建更复杂的请求
err := httpc.New(baseUrl).Path("/dump").Query("param", "value").
Header("MyHeader", "HeaderValue").
AddCookie(&http.Cookie{Name: "cook", Value: "testcook"}).
Body("body data").Post(&resp)
fmt.Println(err)
// fmt.Println(string(resp))
}
Output: <nil>
Example (Error) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
err := httpc.New(baseUrl).Path("not_exist").
SetContext(httpc.NewContext().AddCbOnError(func(client *httpc.HttpC, args ...interface{}) error {
fmt.Println("on error: ", client.Error)
return nil
})).
SuccessStatus(200).Get(nil)
fmt.Println(err)
}
Output: on error: error http status 404 , expect 200 error http status 404 , expect 200
Example (FormBody) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
// struct body
sbody := struct {
Name string `form:"name"`
Age int `form:"age"`
}{
Name: "RecallSong",
Age: 18,
}
var resp string
// 发送form参数
err := httpc.New(baseUrl).Path("echo").
Body(sbody, httpc.TypeApplicationForm). // 将结构体转变为form格式的数据体
Post(&resp)
fmt.Println(err)
fmt.Println(resp)
// map body
mbody := map[string]interface{}{
"name": "RecallSong",
"age": 19,
}
err = httpc.New(baseUrl).Path("echo").
Body(mbody, httpc.TypeApplicationForm). // 将map变为form格式的数据体
Post(&resp)
fmt.Println(err)
fmt.Println(resp)
// url.Values body
ubody := url.Values{}
ubody.Set("name", "RecallSong")
ubody.Set("age", "20")
err = httpc.New(baseUrl).Path("echo").
Body(ubody). // 将url.Values类型转变form格式的数据体
Post(&resp)
fmt.Println(err)
fmt.Println(resp)
}
Output: <nil> age=18&name=RecallSong <nil> age=19&name=RecallSong <nil> age=20&name=RecallSong
Example (Gzip) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
// 测试重试请求
var resp string
err := httpc.New(baseUrl).Path("gzip").Get(&resp)
fmt.Println(err)
fmt.Println(resp)
}
Output: <nil> Hello Hello Hello Hello
Example (Hello) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
var resp string
// 请求 {baseUrl}/hello?name=RecallSong, 并将返回数据读入到resp变量
err := httpc.New(baseUrl).Path("hello").Query("name", "RecallSong").Get(&resp)
fmt.Println(err)
fmt.Println(resp)
}
Output: <nil> Hello, RecallSong
Example (MapBody) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
body := map[string]interface{}{
"name": "RecallSong",
"age": 18,
}
var resp map[string]interface{}
// 根据请求的Content-Type自动对数据进行转换
err := httpc.New(baseUrl).Path("json").
ContentType(httpc.TypeApplicationJson).
Body(body). // body转变为 {"name":"RecallSong","age":18}
Post(&resp) // 根据响应中的Content-Type,将返回的数据解析到resp中
fmt.Println(err)
fmt.Println(resp["name"], resp["age"])
// 如果请求或响应没有指定Content-Type,或是错误的Content-Type,也可以强制指定转换格式类型
err = httpc.New(baseUrl).Path("json").
Body(body, httpc.TypeApplicationJson). // body转变为 {"name":"RecallSong","age":18}
Post(&resp, httpc.TypeApplicationJson) // 将返回的数据按json格式解析到map中
fmt.Println(err)
fmt.Println(resp["name"], resp["age"])
}
Output: <nil> RecallSong 18 <nil> RecallSong 18
Example (Mutipart_map) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
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(baseUrl).Path("echo").
Body(body, httpc.TypeMultipartFormData).Post(&resp)
fmt.Println(err)
// fmt.Println(resp)
}
Output: <nil>
Example (Mutipart_struct) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
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(baseUrl).Path("echo").
Body(body, httpc.TypeMultipartFormData).Post(&resp)
fmt.Println(err)
// fmt.Println(resp)
}
Output: <nil>
Example (Path) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"strings"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
req := httpc.New(baseUrl).EscapedPath("recall/song").EscapedPath(18).DumpRequest()
fmt.Println(strings.Contains(req, "/recall%2Fsong/18"))
}
Output: true
Example (Response) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
var resp *http.Response
// 请求 {baseUrl}/hello?name=RecallSong, 并将返回数据读入到resp变量
err := httpc.New(baseUrl).Path("hello").Query("name", "RecallSong").Get(&resp)
if err != nil {
fmt.Println(err)
} else {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(err, string(body))
}
}
Output: 200 OK <nil> Hello, RecallSong
Example (Retry) ¶
package main
import (
"fmt"
"time"
"github.com/recallsong/httpc"
)
func main() {
// 测试重试请求
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)).
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
Example (StructBody) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
type Person struct {
Name string `json:"name" form:"name" xml:"name"`
Age int `json:"age" form:"age" xml:"age"`
}
func main() {
baseUrl := startServer()
defer stopServer()
body := Person{Name: "RecallSong", Age: 18}
var resp Person
// 可以使用结构体来传递数据
err := httpc.New(baseUrl).Path("echo").
Body(body, httpc.TypeApplicationJson).
Post(&resp, httpc.TypeApplicationJson)
fmt.Println(err)
fmt.Println(resp.Name, resp.Age)
}
Output: <nil> RecallSong 18
Example (Timeout) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
func main() {
baseUrl := startServer()
defer stopServer()
// 测试读数据超时
err := httpc.New(baseUrl).Path("timeout").
SetContext(httpc.NewContext().SetConnectReadTimeout(time.Second, 1*time.Second)).
Get(nil)
fmt.Println(err != nil)
}
Output: true
Example (XmlBody) ¶
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/http/httputil"
"time"
"github.com/recallsong/httpc"
)
type Handler struct {
Method string
Func func(w http.ResponseWriter, r *http.Request)
}
var server *httptest.Server
func startServer() string {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if handler, ok := routers[r.URL.Path]; ok {
if handler.Method != "" && handler.Method != r.Method {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
handler.Func(w, r)
} else {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
}))
return server.URL
}
func stopServer() {
server.Close()
}
var routers = map[string]Handler{
"/hello": Handler{
Method: "GET",
Func: func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, "+r.URL.Query().Get("name"))
},
},
"/dump": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, string(bytes))
},
},
"/echo": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Write(bytes)
},
},
"/json": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
w.Write(bytes)
},
},
"/xml": Handler{
Method: "POST",
Func: func(w http.ResponseWriter, r *http.Request) {
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/xml; charset=UTF-8")
w.Write(bytes)
},
},
"/error": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
},
},
"/timeout": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second)
fmt.Fprintln(w, "Hello")
},
},
"/gzip": Handler{
Func: func(w http.ResponseWriter, r *http.Request) {
var buffer bytes.Buffer
gw := gzip.NewWriter(&buffer)
fmt.Fprintln(gw, "Hello Hello Hello Hello")
gw.Close()
byt := buffer.Bytes()
w.Header().Add("Content-Type", "text/html; charset=utf-8")
w.Header().Add("Content-Length", fmt.Sprint(len(byt)))
w.Header().Add("Content-Encoding", "gzip")
w.Write(byt)
},
},
}
type Person struct {
Name string `json:"name" form:"name" xml:"name"`
Age int `json:"age" form:"age" xml:"age"`
}
func main() {
baseUrl := startServer()
defer stopServer()
body := Person{Name: "RecallSong", Age: 18}
var resp Person
// 发送和接收xml数据
err := httpc.New(baseUrl).Path("xml").
Body(body, httpc.TypeApplicationXml). // 数据转变为xml格式
Post(&resp)
fmt.Println(err)
fmt.Println(resp)
}
Output: <nil> {RecallSong 18}
func (*HttpC) ContentType ¶
ContentType 设置http头中的Content-Type
func (*HttpC) DumpRequest ¶
DumpRequest 将http请求明细输出为string
func (*HttpC) DumpResponse ¶
DumpResponse 将http请求明细输出为string
func (*HttpC) EscapedPath ¶
EscapedPath 对path进行url编码后,再追加到当前的url上
func (*HttpC) SuccessStatus ¶
SuccessStatus 设置成功的状态码
type ReqBodyReader ¶
type ReqBodyReader func(req *http.Request, typ reflect.Type, data interface{}) (io.ReadCloser, error)
ReqBodyReader 根据类型将数据转换为reader
type RespBodyReader ¶
type RespBodyReader func(resp *http.Response, reader io.ReadCloser, typ reflect.Type, out interface{}) error
RespBodyReader 根据类型将数据读取到out中