1.依赖包


          
          
import "github.com/dghubble/sling"
  • 1.

2.功能介绍

​项目开发中,发送http请求的场景,推荐使用Sling库。Sling本身是基于net/http来处理发送请求,同时做了较好的封装,既可以利用net/http的一些特性(如:httptrace),同时又不必关心net/http库的一些琐碎细节。Sling对http请求的要素method、baseUrl、Path、query、body、request、response等做了封装,基本使用可以参考https://github.com/dghubble/sling 上的示例代码。​

#yyds干货盘点#详解Go http client库-Sling实现http接口调用_sed


          
          
type Sling struct {
// http Client for doing requests
httpClient Doer
// HTTP method (GET, POST, etc.)
method string
// raw url string for requests
rawURL string
// stores key-values pairs to add to request's Headers
header http . Header
// url tagged query structs
queryStructs [] interface{}
// body provider
bodyProvider BodyProvider
// response decoder
responseDecoder ResponseDecoder
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

          
          
// Request returns a new http.Request created with the Sling properties.
// Returns any errors parsing the rawURL, encoding query structs, encoding
// the body, or creating the http.Request.
func ( s * Sling) Request() ( * http . Request, error) {
reqURL, err : = url . Parse( s . rawURL)
if err != nil {
return nil, err
}

err = addQueryStructs( reqURL, s . queryStructs)
if err != nil {
return nil, err
}

var body io . Reader
if s . bodyProvider != nil {
body, err = s . bodyProvider . Body()
if err != nil {
return nil, err
}
}
req, err : = http . NewRequest( s . method, reqURL . String(), body)
if err != nil {
return nil, err
}
addHeaders( req, s . header)
return req, err
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

api_path转换为url

#yyds干货盘点#详解Go http client库-Sling实现http接口调用_sed_02

#yyds干货盘点#详解Go http client库-Sling实现http接口调用_sed_03

3.使用方法

#yyds干货盘点#详解Go http client库-Sling实现http接口调用_ide_04

#yyds干货盘点#详解Go http client库-Sling实现http接口调用_json_05


          
          
package httputil

import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
"sync"
"time"

"github.com/dghubble/sling"
"github.com/emicklei/go-restful"
)

const (
jsonAcceptHeader = "application/json"
testAcceptHeader = "text/plain"
clientNumsPerHost = 30
)

type HttpPoolMgr struct {
maxConns int
cacheClient map[ string] * HttpPool
}

var httpPoolMgr * HttpPoolMgr

func ( this * HttpPoolMgr) Borrow( host string) ( * http . Client, error) {
if httpPool, ok : = this . cacheClient[ host]; ok {
return httpPool . Borrow()
} else {
httpPool : = newHttpPool()
httpPool . host = host
this . cacheClient[ host] = httpPool
return httpPool . Borrow()
}
}

func ( this * HttpPoolMgr) Return( host string, c * http . Client) {
if httpPool, ok : = this . cacheClient[ host]; ok {
httpPool . Return( c)
return
} else {
httpPool : = newHttpPool()
httpPool . host = host
this . cacheClient[ host] = httpPool
httpPool . Return( c)
return
}
}

//var httpPool *HttpPool
type HttpPool struct {
host string
pool chan * http . Client
used int
l * sync . Mutex
}

func newHttpPool() * HttpPool {
httpPool : = & HttpPool{}
httpPool . pool = make( chan * http . Client, clientNumsPerHost)
httpPool . l = & sync . Mutex{}
return httpPool
}

func ( this * HttpPool) Return( c * http . Client) {
this . used --
if len( this . pool) < clientNumsPerHost {
this . pool <- c
}
}

func ( this * HttpPool) Borrow() ( * http . Client, error) {

if client : = this . innerBorrow(); client != nil {
return client, nil
}

i : = 1
for {
i ++
time . Sleep( 500 * time . Millisecond)
if client : = this . innerBorrow(); client != nil {
return client, nil
}

//池中无
if i > 5 {
return nil, errors . New( fmt . Sprintf( "Can not get conn to [%s] from cache.", this . host))
}

}
}

func ( this * HttpPool) innerBorrow() * http . Client {
select {
case c : = <- this . pool:
this . used ++
return c
default:
this . l . Lock()
defer this . l . Unlock()
if this . used < clientNumsPerHost {
this . used ++
return & http . Client{}
}
}

return nil
}

func InitHttpTool() {
http . DefaultTransport .( * http . Transport) . MaxIdleConns = 20000
http . DefaultTransport .( * http . Transport) . MaxIdleConnsPerHost = 1000
http . DefaultTransport .( * http . Transport) . DisableKeepAlives = false
http . DefaultTransport .( * http . Transport) . IdleConnTimeout = 2 * time . Minute

httpPoolMgr = & HttpPoolMgr{}
httpPoolMgr . cacheClient = make( map[ string] * HttpPool)
}

func Request( method string, api_path string, model interface{}, headers map[ string] string) ( int, [] byte, error) {
_sling : = sling . New()
if strings . ToLower( method) == "post" {
_sling = _sling . Post( api_path)
// create path and map variables
//path := "/api/users/"
//
//_sling = _sling.Path(path)

// body params
_sling = _sling . BodyJSON( model)
} else if strings . ToLower( method) == "get" {
_sling = _sling . Get( api_path)
} else if strings . ToLower( method) == "put" {
_sling = _sling . Put( api_path)
if model != nil && model != "" {
_sling = _sling . BodyJSON( model)
}
} else if strings . ToLower( method) == "head" {
_sling = _sling . Head( api_path)
} else if strings . ToLower( method) == "delete" {
_sling = _sling . Delete( api_path)
}
if headers == nil {
headers = make( map[ string] string)
}

headers[ "Content-Type"] = jsonAcceptHeader
httpStatusCode, body, err : = request( _sling, headers)
return httpStatusCode, body, err
}

func HttpRequest( method string, api_path string, model interface{}, req * restful . Request) ( int, [] byte, error) {
authorization : = req . HeaderParameter( "Authorization")
return Request( method, api_path, model, map[ string] string{ "Authorization": authorization})

}

func HttpRequsetText( method string, api_path string, text io . Reader, headers map[ string] string) ( int, [] byte, error) {
_sling : = sling . New()
if strings . ToLower( method) == "post" {
_sling : = _sling . Post( api_path)
// create path and map variables
//path := "/api/users/"
//
//_sling = _sling.Path(path)

// body params
_sling = _sling . Body( text)
}
if headers == nil {
headers = make( map[ string] string)
}
headers[ "Content-Type"] = jsonAcceptHeader
httpStatusCode, body, err : = request( _sling, headers)
return httpStatusCode, body, err
}

func request( _sling * sling . Sling, headers map[ string] string) ( int, [] byte, error) {
for k, v : = range headers {
_sling = _sling . Set( k, v)
}
req, err : = _sling . Request()
if err != nil {
return 400, nil, err
}

host : = req . Host
if host == "" {
return 500, nil, errors . New( "the req's host cannot be empty.")
}
client, err : = httpPoolMgr . Borrow( host)
if err != nil {
//panic(err)
return 500, nil, err
}
defer httpPoolMgr . Return( host, client)
resp, err : = client . Do( req)
if err != nil {
return 500, nil, err
}
defer resp . Body . Close()
body, err : = ioutil . ReadAll( resp . Body)
if err != nil {
// handle error
return resp . StatusCode, body, err
}

if 500 == resp . StatusCode {

log . Println( errors . New( string( body)))
return resp . StatusCode, body, errors . New( string( body))
}

return resp . StatusCode, body, err

}

func PostRequest( url string, model interface{}, headers map[ string] string) ( status int, respBytes [] byte, err error) {
status, respBytes, err = Request( "POST", url, model, headers)
return
}

func GetRequest( url string, model interface{}, headers map[ string] string) ( status int, respBytes [] byte, err error) {
status, respBytes, err = Request( "GET", url, model, headers)
return
}

type TLSConfig struct {
CAFile string
CertFile string
KeyFile string
ServerName string
InsecureSkipVerify bool
}

func NewTLSConfig( cfg * TLSConfig) ( * tls . Config, error) {
tlsConfig : = & tls . Config{ InsecureSkipVerify: cfg . InsecureSkipVerify}

if len( cfg . CAFile) > 0 {
caCertPool : = x509 . NewCertPool()
caCert, err : = ioutil . ReadFile( cfg . CAFile)
if err != nil {
return nil, fmt . Errorf( "unable to use specified CA cert %s: %s", cfg . CAFile, err)
}
caCertPool . AppendCertsFromPEM( caCert)
tlsConfig . RootCAs = caCertPool
}

if len( cfg . ServerName) > 0 {
tlsConfig . ServerName = cfg . ServerName
}
if len( cfg . CertFile) > 0 && len( cfg . KeyFile) == 0 {
return nil, fmt . Errorf( "client cert file %q specified without client key file", cfg . CertFile)
} else if len( cfg . KeyFile) > 0 && len( cfg . CertFile) == 0 {
return nil, fmt . Errorf( "client key file %q specified without client cert file", cfg . KeyFile)
} else if len( cfg . CertFile) > 0 && len( cfg . KeyFile) > 0 {
cert, err : = tls . LoadX509KeyPair( cfg . CertFile, cfg . KeyFile)
if err != nil {
return nil, fmt . Errorf( "unable to use specified client cert (%s) & key (%s): %s", cfg . CertFile, cfg . KeyFile, err)
}
tlsConfig . Certificates = [] tls . Certificate{ cert}
}
tlsConfig . BuildNameToCertificate()

return tlsConfig, nil
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.