You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gorequest/http.go

384 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package gorequest
import (
"bytes"
"compress/flate"
"compress/gzip"
"context"
"crypto/tls"
"errors"
"fmt"
cookiemonster "github.com/MercuryEngineering/CookieMonster"
"go.dtapp.net/gojson"
"go.dtapp.net/gotime"
"go.dtapp.net/gotrace_id"
"io"
"log"
"net/http"
"net/url"
"strings"
"time"
)
// Response 返回内容
type Response struct {
RequestId string //【请求】编号
RequestUri string //【请求】链接
RequestParams Params //【请求】参数
RequestMethod string //【请求】方式
RequestHeader Headers //【请求】头部
RequestCookie string //【请求】Cookie
RequestTime time.Time //【请求】时间
ResponseHeader http.Header //【返回】头部
ResponseStatus string //【返回】状态
ResponseStatusCode int //【返回】状态码
ResponseBody []byte //【返回】内容
ResponseContentLength int64 //【返回】大小
ResponseTime time.Time //【返回】时间
}
// App 实例
type App struct {
Uri string // 全局请求地址没有设置url才会使用
Error error // 错误
httpUri string // 请求地址
httpMethod string // 请求方法
httpHeader Headers // 请求头
httpParams Params // 请求参数
httpCookie string // Cookie
responseContent Response // 返回内容
httpContentType string // 请求内容类型
debug bool // 是否开启调试模式
p12Cert *tls.Certificate // p12证书内容
tlsMinVersion, tlsMaxVersion uint16 // TLS版本
}
// NewHttp 实例化
func NewHttp() *App {
app := &App{
httpHeader: NewHeaders(),
httpParams: NewParams(),
}
return app
}
// SetDebug 设置调试模式
func (app *App) SetDebug() {
app.debug = true
}
// SetUri 设置请求地址
func (app *App) SetUri(uri string) {
if uri != "" {
app.httpUri = uri
}
}
// SetMethod 设置请求方式
func (app *App) SetMethod(method string) {
if method != "" {
app.httpMethod = method
}
}
// SetHeader 设置请求头
func (app *App) SetHeader(key, value string) {
app.httpHeader.Set(key, value)
}
// SetHeaders 批量设置请求头
func (app *App) SetHeaders(headers Headers) {
for key, value := range headers {
app.httpHeader.Set(key, value)
}
}
// SetTlsVersion 设置TLS版本
func (app *App) SetTlsVersion(minVersion, maxVersion uint16) {
app.tlsMinVersion = minVersion
app.tlsMaxVersion = maxVersion
}
// SetAuthToken 设置身份验证令牌
func (app *App) SetAuthToken(token string) {
if token != "" {
app.httpHeader.Set("Authorization", fmt.Sprintf("Bearer %s", token))
}
}
// SetUserAgent 设置用户代理,传空字符串就随机设置
func (app *App) SetUserAgent(ua string) {
if ua != "" {
app.httpHeader.Set("User-Agent", ua)
}
}
// SetContentTypeJson 设置JSON格式
func (app *App) SetContentTypeJson() {
app.httpContentType = httpParamsModeJson
}
// SetContentTypeForm 设置FORM格式
func (app *App) SetContentTypeForm() {
app.httpContentType = httpParamsModeForm
}
// SetContentTypeXml 设置XML格式
func (app *App) SetContentTypeXml() {
app.httpContentType = httpParamsModeXml
}
// SetParam 设置请求参数
func (app *App) SetParam(key string, value interface{}) {
app.httpParams.Set(key, value)
}
// SetParams 批量设置请求参数
func (app *App) SetParams(params Params) {
for key, value := range params {
app.httpParams.Set(key, value)
}
}
// SetCookie 设置Cookie
func (app *App) SetCookie(cookie string) {
if cookie != "" {
app.httpCookie = cookie
}
}
// SetP12Cert 设置证书
func (app *App) SetP12Cert(content *tls.Certificate) {
app.p12Cert = content
}
// Get 发起GET请求
func (app *App) Get(ctx context.Context, uri ...string) (httpResponse Response, err error) {
if len(uri) == 1 {
app.Uri = uri[0]
}
// 设置请求方法
app.httpMethod = http.MethodGet
return request(app, ctx)
}
// Post 发起POST请求
func (app *App) Post(ctx context.Context, uri ...string) (httpResponse Response, err error) {
if len(uri) == 1 {
app.Uri = uri[0]
}
// 设置请求方法
app.httpMethod = http.MethodPost
return request(app, ctx)
}
// Request 发起请求
func (app *App) Request(ctx context.Context) (httpResponse Response, err error) {
return request(app, ctx)
}
// 请求接口
func request(app *App, ctx context.Context) (httpResponse Response, err error) {
// 赋值
httpResponse.RequestTime = gotime.Current().Time
httpResponse.RequestUri = app.httpUri
httpResponse.RequestMethod = app.httpMethod
httpResponse.RequestParams = app.httpParams.DeepCopy()
httpResponse.RequestHeader = app.httpHeader.DeepCopy()
httpResponse.RequestCookie = app.httpCookie
// 判断网址
if httpResponse.RequestUri == "" {
httpResponse.RequestUri = app.Uri
}
if httpResponse.RequestUri == "" {
app.Error = errors.New("没有设置Uri")
if app.debug {
log.Printf("{%s}------------------------\n", gotrace_id.GetTraceIdContext(ctx))
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
// 创建 http 客户端
client := &http.Client{}
transportStatus := false
transport := &http.Transport{}
transportTls := &tls.Config{}
if app.p12Cert != nil {
transportStatus = true
// 配置
transportTls.Certificates = []tls.Certificate{*app.p12Cert}
transport.DisableCompression = true
}
if app.tlsMinVersion != 0 && app.tlsMaxVersion != 0 {
transportStatus = true
// 配置
transportTls.MinVersion = app.tlsMinVersion
transportTls.MaxVersion = app.tlsMaxVersion
}
if transportStatus {
transport.TLSClientConfig = transportTls
client = &http.Client{
Transport: transport,
}
}
// 请求类型
if app.httpContentType == "" {
app.httpContentType = httpParamsModeJson
}
switch app.httpContentType {
case httpParamsModeJson:
httpResponse.RequestHeader.Set("Content-Type", "application/json")
case httpParamsModeForm:
httpResponse.RequestHeader.Set("Content-Type", "application/x-www-form-urlencoded")
case httpParamsModeXml:
httpResponse.RequestHeader.Set("Content-Type", "text/xml")
}
// 跟踪编号
httpResponse.RequestId = gotrace_id.GetTraceIdContext(ctx)
if httpResponse.RequestId != "" {
httpResponse.RequestHeader.Set("X-Request-Id", httpResponse.RequestId)
}
// 请求内容
var reqBody io.Reader
if httpResponse.RequestMethod == http.MethodPost && app.httpContentType == httpParamsModeJson {
jsonStr, err := gojson.Marshal(httpResponse.RequestParams)
if err != nil {
app.Error = errors.New(fmt.Sprintf("解析出错 %s", err))
if app.debug {
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
// 赋值
reqBody = bytes.NewBuffer(jsonStr)
}
if httpResponse.RequestMethod == http.MethodPost && app.httpContentType == httpParamsModeForm {
// 携带 form 参数
form := url.Values{}
for k, v := range httpResponse.RequestParams {
form.Add(k, GetParamsString(v))
}
// 赋值
reqBody = strings.NewReader(form.Encode())
}
if app.httpContentType == httpParamsModeXml {
reqBody, err = ToXml(httpResponse.RequestParams)
if err != nil {
app.Error = errors.New(fmt.Sprintf("解析XML出错 %s", err))
if app.debug {
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
}
// 创建请求
req, err := http.NewRequest(httpResponse.RequestMethod, httpResponse.RequestUri, reqBody)
if err != nil {
app.Error = errors.New(fmt.Sprintf("创建请求出错 %s", err))
if app.debug {
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
// GET 请求携带查询参数
if httpResponse.RequestMethod == http.MethodGet {
q := req.URL.Query()
for k, v := range httpResponse.RequestParams {
q.Add(k, GetParamsString(v))
}
req.URL.RawQuery = q.Encode()
}
// 设置请求头
if len(httpResponse.RequestHeader) > 0 {
for key, value := range httpResponse.RequestHeader {
req.Header.Set(key, fmt.Sprintf("%v", value))
}
}
// 设置Cookie
if httpResponse.RequestCookie != "" {
cookies, _ := cookiemonster.ParseString(httpResponse.RequestCookie)
if len(cookies) > 0 {
for _, c := range cookies {
req.AddCookie(c)
}
} else {
req.Header.Set("Cookie", httpResponse.RequestCookie)
}
}
if app.debug {
log.Printf("{%s}请求Uri%s %s\n", httpResponse.RequestId, httpResponse.RequestMethod, httpResponse.RequestUri)
log.Printf("{%s}请求Params Get%+v\n", httpResponse.RequestId, req.URL.RawQuery)
log.Printf("{%s}请求Params Post%+v\n", httpResponse.RequestId, reqBody)
log.Printf("{%s}请求Header%+v\n", httpResponse.RequestId, req.Header)
}
// 发送请求
resp, err := client.Do(req)
if err != nil {
app.Error = errors.New(fmt.Sprintf("请求出错 %s", err))
if app.debug {
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
// 最后关闭连接
defer resp.Body.Close()
var reader io.ReadCloser
switch resp.Header.Get("Content-Encoding") {
case "gzip":
reader, _ = gzip.NewReader(resp.Body)
case "deflate":
reader = flate.NewReader(resp.Body)
default:
reader = resp.Body
}
defer reader.Close() // nolint
// 读取内容
body, err := io.ReadAll(reader)
if err != nil {
app.Error = errors.New(fmt.Sprintf("解析内容出错 %s", err))
if app.debug {
log.Printf("{%s}请求异常:%v\n", httpResponse.RequestId, app.Error)
}
return httpResponse, app.Error
}
// 赋值
httpResponse.ResponseTime = gotime.Current().Time
httpResponse.ResponseStatus = resp.Status
httpResponse.ResponseStatusCode = resp.StatusCode
httpResponse.ResponseHeader = resp.Header
httpResponse.ResponseBody = body
httpResponse.ResponseContentLength = resp.ContentLength
if app.debug {
log.Printf("{%s}返回Status%s\n", httpResponse.RequestId, httpResponse.ResponseStatus)
log.Printf("{%s}返回Header%+v\n", httpResponse.RequestId, httpResponse.ResponseHeader)
log.Printf("{%s}返回Body%s\n", httpResponse.RequestId, httpResponse.ResponseBody)
log.Printf("{%s}------------------------\n", gotrace_id.GetTraceIdContext(ctx))
}
return httpResponse, err
}