github.com/zhongdalu/gf@v1.0.0/g/net/ghttp/ghttp_client_request.go (about) 1 // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // HTTP客户端请求. 8 9 package ghttp 10 11 import ( 12 "bytes" 13 "crypto/tls" 14 "encoding/json" 15 "errors" 16 "fmt" 17 "io" 18 "mime/multipart" 19 "net/http" 20 "os" 21 "strings" 22 "time" 23 24 "github.com/zhongdalu/gf/g/os/gfile" 25 ) 26 27 // http客户端 28 type Client struct { 29 http.Client // 底层http client对象 30 header map[string]string // HEADER信息Map 31 cookies map[string]string // 自定义COOKIE 32 prefix string // 设置请求的URL前缀 33 authUser string // HTTP基本权限设置:名称 34 authPass string // HTTP基本权限设置:密码 35 browserMode bool // 是否模拟浏览器模式(自动保存提交COOKIE) 36 retryCount int // 失败重试次数(网络失败情况下) 37 retryInterval int // 失败重试间隔 38 } 39 40 // http客户端对象指针 41 func NewClient() *Client { 42 return &Client{ 43 Client: http.Client{ 44 Transport: &http.Transport{ 45 // 默认不校验HTTPS证书有效性 46 TLSClientConfig: &tls.Config{ 47 InsecureSkipVerify: true, 48 }, 49 // 默认关闭KeepAlive功能 50 DisableKeepAlives: true, 51 }, 52 }, 53 header: make(map[string]string), 54 cookies: make(map[string]string), 55 } 56 } 57 58 // 克隆当前客户端对象,复制属性。 59 func (c *Client) Clone() *Client { 60 newClient := NewClient() 61 *newClient = *c 62 newClient.header = make(map[string]string) 63 newClient.cookies = make(map[string]string) 64 for k, v := range c.header { 65 newClient.header[k] = v 66 } 67 for k, v := range c.cookies { 68 newClient.cookies[k] = v 69 } 70 return newClient 71 } 72 73 // GET请求 74 func (c *Client) Get(url string) (*ClientResponse, error) { 75 return c.DoRequest("GET", url) 76 } 77 78 // PUT请求 79 func (c *Client) Put(url string, data ...interface{}) (*ClientResponse, error) { 80 return c.DoRequest("PUT", url, data...) 81 } 82 83 // POST请求提交数据,默认使用表单方式提交数据(绝大部分场景下也是如此)。 84 // 如果服务端对Content-Type有要求,可使用Client对象进行请求,单独设置相关属性。 85 // 支持文件上传,需要字段格式为:FieldName=@file: 86 func (c *Client) Post(url string, data ...interface{}) (resp *ClientResponse, err error) { 87 if len(c.prefix) > 0 { 88 url = c.prefix + url 89 } 90 param := "" 91 if len(data) > 0 { 92 param = BuildParams(data[0]) 93 } 94 req := (*http.Request)(nil) 95 if strings.Contains(param, "@file:") { 96 // 文件上传 97 buffer := new(bytes.Buffer) 98 writer := multipart.NewWriter(buffer) 99 for _, item := range strings.Split(param, "&") { 100 array := strings.Split(item, "=") 101 if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 { 102 path := array[1][6:] 103 if !gfile.Exists(path) { 104 return nil, errors.New(fmt.Sprintf(`"%s" does not exist`, path)) 105 } 106 if file, err := writer.CreateFormFile(array[0], path); err == nil { 107 if f, err := os.Open(path); err == nil { 108 defer f.Close() 109 if _, err = io.Copy(file, f); err != nil { 110 return nil, err 111 } 112 } else { 113 return nil, err 114 } 115 } else { 116 return nil, err 117 } 118 } else { 119 writer.WriteField(array[0], array[1]) 120 } 121 } 122 writer.Close() 123 if req, err = http.NewRequest("POST", url, buffer); err != nil { 124 return nil, err 125 } else { 126 req.Header.Set("Content-Type", writer.FormDataContentType()) 127 } 128 } else { 129 // 普通请求 130 paramBytes := []byte(param) 131 if req, err = http.NewRequest("POST", url, bytes.NewReader(paramBytes)); err != nil { 132 return nil, err 133 } else { 134 if v, ok := c.header["Content-Type"]; ok { 135 // 自定义请求类型 136 req.Header.Set("Content-Type", v) 137 } else { 138 // 识别提交数据格式 139 if json.Valid(paramBytes) { 140 req.Header.Set("Content-Type", "application/json") 141 } else { 142 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 143 } 144 } 145 } 146 } 147 // 自定义header 148 if len(c.header) > 0 { 149 for k, v := range c.header { 150 req.Header.Set(k, v) 151 } 152 } 153 // COOKIE 154 if len(c.cookies) > 0 { 155 headerCookie := "" 156 for k, v := range c.cookies { 157 if len(headerCookie) > 0 { 158 headerCookie += ";" 159 } 160 headerCookie += k + "=" + v 161 } 162 if len(headerCookie) > 0 { 163 req.Header.Set("Cookie", headerCookie) 164 } 165 } 166 // HTTP账号密码 167 if len(c.authUser) > 0 { 168 req.SetBasicAuth(c.authUser, c.authPass) 169 } 170 // 执行请求 171 r := (*http.Response)(nil) 172 for { 173 if r, err = c.Do(req); err != nil { 174 if c.retryCount > 0 { 175 c.retryCount-- 176 } else { 177 return nil, err 178 } 179 } else { 180 break 181 } 182 } 183 resp = &ClientResponse{ 184 cookies: make(map[string]string), 185 } 186 resp.Response = r 187 // 浏览器模式 188 if c.browserMode { 189 now := time.Now() 190 for _, v := range r.Cookies() { 191 if v.Expires.UnixNano() < now.UnixNano() { 192 delete(c.cookies, v.Name) 193 } else { 194 c.cookies[v.Name] = v.Value 195 } 196 } 197 } 198 return resp, nil 199 } 200 201 // DELETE请求 202 func (c *Client) Delete(url string, data ...interface{}) (*ClientResponse, error) { 203 return c.DoRequest("DELETE", url, data...) 204 } 205 206 func (c *Client) Head(url string, data ...interface{}) (*ClientResponse, error) { 207 return c.DoRequest("HEAD", url, data...) 208 } 209 210 func (c *Client) Patch(url string, data ...interface{}) (*ClientResponse, error) { 211 return c.DoRequest("PATCH", url, data...) 212 } 213 214 func (c *Client) Connect(url string, data ...interface{}) (*ClientResponse, error) { 215 return c.DoRequest("CONNECT", url, data...) 216 } 217 218 func (c *Client) Options(url string, data ...interface{}) (*ClientResponse, error) { 219 return c.DoRequest("OPTIONS", url, data...) 220 } 221 222 func (c *Client) Trace(url string, data ...interface{}) (*ClientResponse, error) { 223 return c.DoRequest("TRACE", url, data...) 224 } 225 226 // GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针) 227 func (c *Client) GetContent(url string, data ...interface{}) string { 228 return c.DoRequestContent("GET", url, data...) 229 } 230 231 // PUT请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针) 232 func (c *Client) PutContent(url string, data ...interface{}) string { 233 return c.DoRequestContent("PUT", url, data...) 234 } 235 236 // POST请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针) 237 func (c *Client) PostContent(url string, data ...interface{}) string { 238 return c.DoRequestContent("POST", url, data...) 239 } 240 241 // DELETE请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针) 242 func (c *Client) DeleteContent(url string, data ...interface{}) string { 243 return c.DoRequestContent("DELETE", url, data...) 244 } 245 246 func (c *Client) HeadContent(url string, data ...interface{}) string { 247 return c.DoRequestContent("HEAD", url, data...) 248 } 249 250 func (c *Client) PatchContent(url string, data ...interface{}) string { 251 return c.DoRequestContent("PATCH", url, data...) 252 } 253 254 func (c *Client) ConnectContent(url string, data ...interface{}) string { 255 return c.DoRequestContent("CONNECT", url, data...) 256 } 257 258 func (c *Client) OptionsContent(url string, data ...interface{}) string { 259 return c.DoRequestContent("OPTIONS", url, data...) 260 } 261 262 func (c *Client) TraceContent(url string, data ...interface{}) string { 263 return c.DoRequestContent("TRACE", url, data...) 264 } 265 266 // 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针) 267 func (c *Client) DoRequestContent(method string, url string, data ...interface{}) string { 268 response, err := c.DoRequest(method, url, data...) 269 if err != nil { 270 return "" 271 } 272 defer response.Close() 273 return string(response.ReadAll()) 274 } 275 276 // 请求并返回response对象 277 func (c *Client) DoRequest(method, url string, data ...interface{}) (*ClientResponse, error) { 278 if strings.EqualFold("POST", method) { 279 return c.Post(url, data...) 280 } 281 if len(c.prefix) > 0 { 282 url = c.prefix + url 283 } 284 param := "" 285 if len(data) > 0 { 286 param = BuildParams(data[0]) 287 } 288 req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader([]byte(param))) 289 if err != nil { 290 return nil, err 291 } 292 // 自定义header 293 if len(c.header) > 0 { 294 for k, v := range c.header { 295 req.Header.Set(k, v) 296 } 297 } 298 // COOKIE 299 if len(c.cookies) > 0 { 300 headerCookie := "" 301 for k, v := range c.cookies { 302 if len(headerCookie) > 0 { 303 headerCookie += ";" 304 } 305 headerCookie += k + "=" + v 306 } 307 if len(headerCookie) > 0 { 308 req.Header.Set("Cookie", headerCookie) 309 } 310 } 311 // 执行请求 312 resp := (*http.Response)(nil) 313 for { 314 if r, err := c.Do(req); err != nil { 315 if c.retryCount > 0 { 316 c.retryCount-- 317 } else { 318 return nil, err 319 } 320 } else { 321 resp = r 322 break 323 } 324 } 325 r := &ClientResponse{ 326 cookies: make(map[string]string), 327 } 328 r.Response = resp 329 // 浏览器模式 330 if c.browserMode { 331 now := time.Now() 332 for _, v := range r.Cookies() { 333 if v.Expires.UnixNano() < now.UnixNano() { 334 delete(c.cookies, v.Name) 335 } else { 336 c.cookies[v.Name] = v.Value 337 } 338 } 339 } 340 //fmt.Println(url, c.cookies) 341 return r, nil 342 }