gitee.com/quant1x/gox@v1.21.2/http/request.go (about) 1 package http 2 3 import ( 4 "bytes" 5 "compress/flate" 6 "compress/gzip" 7 "fmt" 8 "gitee.com/quant1x/gox/api" 9 "gitee.com/quant1x/gox/exception" 10 "gitee.com/quant1x/gox/logger" 11 "io" 12 "maps" 13 "net/http" 14 URL "net/url" 15 "strings" 16 "time" 17 ) 18 19 const ( 20 MethodGet = http.MethodGet 21 MethodPost = http.MethodPost 22 MethodHead = http.MethodHead 23 MethodPut = http.MethodPut 24 MethodPatch = http.MethodPatch // RFC 5789 25 MethodDelete = http.MethodDelete 26 MethodConnect = http.MethodConnect 27 MethodOptions = http.MethodOptions 28 MethodTrace = http.MethodTrace 29 30 ContentEncoding = "Content-Encoding" 31 ContextType = "Content-Type" 32 LastModified = "Last-Modified" 33 IfModifiedSince = "If-Modified-Since" 34 charsetUtf8 = "charset=UTF-8" 35 ApplicationJson = "application/json" + ";" + charsetUtf8 36 ApplicationForm = "application/x-www-form-urlencoded" + ";" + charsetUtf8 37 ) 38 39 var ( 40 TimeZero = time.Unix(0, 0) 41 NotFound = exception.New(http.StatusNotFound, http.StatusText(http.StatusNotFound)) 42 ) 43 44 var ( 45 defaultHeaders = map[string]string{ 46 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", 47 "Accept-Encoding": "gzip, deflate", 48 "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 49 "Cache-Control": "no-cache", 50 "Connection": "keep-alive", 51 "Pragma": "no-cache", 52 "Upgrade-Insecure-Requests": "1", 53 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35", 54 } 55 ) 56 57 // HttpRequest HTTP 请求 58 func HttpRequest(url string, method string, header ...map[string]any) ([]byte, error) { 59 data, lastModified, err := Request(url, method, "", header...) 60 _ = lastModified 61 return data, err 62 } 63 64 // Get HTTP协议GET请求 65 func Get(url string, header ...map[string]any) ([]byte, error) { 66 data, _, err := Request(url, MethodGet, "", header...) 67 return data, err 68 } 69 70 // Post HTTP协议POST请求 71 func Post(url string, content string, header ...map[string]any) (data []byte, err error) { 72 var requestHeader map[string]any 73 if len(header) == 0 { 74 requestHeader = make(map[string]any, 0) 75 } else { 76 requestHeader = header[0] 77 } 78 requestHeader[ContextType] = ApplicationForm 79 content = strings.TrimSpace(content) 80 length := len(content) 81 if length >= 2 { 82 // json 最短长度为2 83 start := content[0] 84 end := content[length-1] 85 if (start == '{' && end == '}') || (start == '[' && end == ']') { 86 // 这是json 87 requestHeader[ContextType] = ApplicationJson 88 } 89 } 90 data, _, err = Request(url, MethodPost, content, requestHeader) 91 return data, err 92 } 93 94 // Request http request, 支持传入header 95 func Request(url string, method string, content string, header ...map[string]any) (data []byte, lastModified time.Time, err error) { 96 u, err := URL.Parse(url) 97 if err != nil { 98 return nil, TimeZero, err 99 } 100 reqHeader := maps.Clone(defaultHeaders) 101 reqHeader["Host"] = u.Host 102 if len(header) > 0 { 103 mapHeader := header[0] 104 for k, v := range mapHeader { 105 switch val := v.(type) { 106 case time.Time: 107 val = val.UTC() 108 reqHeader[k] = val.Format(time.RFC1123) 109 case float32, float64: 110 reqHeader[k] = fmt.Sprintf("%f", val) 111 case int8, int16, int32, int64: 112 reqHeader[k] = fmt.Sprintf("%d", val) 113 case uint8, uint16, uint32, uint64: 114 reqHeader[k] = fmt.Sprintf("%d", val) 115 case string: 116 reqHeader[k] = val 117 default: 118 reqHeader[k] = fmt.Sprintf("%v", val) 119 } 120 } 121 } 122 123 client := defaultClient() 124 var requestBody io.Reader = nil 125 if len(content) > 0 { 126 requestBody = strings.NewReader(content) 127 } 128 request, err := http.NewRequest(strings.ToUpper(method), url, requestBody) 129 if err != nil { 130 return nil, TimeZero, err 131 } 132 for key, v := range reqHeader { 133 request.Header.Add(key, v) 134 } 135 136 response, err := client.Do(request) 137 if err != nil { 138 return nil, TimeZero, err 139 } 140 if response.StatusCode == http.StatusNotFound { 141 return nil, TimeZero, NotFound 142 } 143 lm := response.Header.Get(LastModified) 144 if response.StatusCode == http.StatusNotModified && !api.IsEmpty(lm) { 145 return nil, TimeZero, nil 146 } 147 lastModified, err = time.Parse(time.RFC1123, lm) 148 defer api.CloseQuietly(response.Body) 149 body, err := io.ReadAll(response.Body) 150 if err != nil { 151 return nil, TimeZero, err 152 } 153 contentEncoding := response.Header.Get(ContentEncoding) 154 var reader io.ReadCloser = nil 155 if len(contentEncoding) > 0 { 156 contentEncoding = strings.ToLower(contentEncoding) 157 switch contentEncoding { 158 case "gzip": 159 reader, err = gzip.NewReader(bytes.NewBuffer(body)) 160 if err != nil { 161 logger.Error(err) 162 reader = nil 163 } 164 case "deflate": 165 reader = flate.NewReader(bytes.NewReader(body)) 166 } 167 } 168 if reader != nil { 169 defer api.CloseQuietly(reader) 170 body, err = io.ReadAll(reader) 171 if err != nil { 172 return nil, TimeZero, err 173 } 174 } 175 return body, lastModified, nil 176 }