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 上的示例代码。
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
3.使用方法
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.