131 lines
3.6 KiB
Go
131 lines
3.6 KiB
Go
|
package request
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// 请求结构体
|
||
|
type Request struct {
|
||
|
Method string `json:"method"` // 请求方法
|
||
|
Url string `json:"url"` // 请求url
|
||
|
Params map[string]string `json:"params"` // Query参数
|
||
|
Headers map[string]string `json:"headers"` // 请求头
|
||
|
Cookies map[string]string `json:"cookies"` // todo 处理 Cookies
|
||
|
Data map[string]string `json:"data"` // 表单格式请求数据
|
||
|
Json map[string]string `json:"json"` // JSON格式请求数据 todo 多层 嵌套
|
||
|
Files map[string]string `json:"files"` // todo 处理 Files
|
||
|
Raw string `json:"raw"` // 原始请求数据
|
||
|
JsonByte []byte `json:"json_raw"` // JSON格式请求数据 todo 多层 嵌套
|
||
|
}
|
||
|
|
||
|
// 响应结构体
|
||
|
type Response struct {
|
||
|
StatusCode int `json:"status_code"` // 状态码
|
||
|
Reason string `json:"reason"` // 状态码说明
|
||
|
Elapsed float64 `json:"elapsed"` // 请求耗时(秒)
|
||
|
Content []byte `json:"content"` // 响应二进制内容
|
||
|
Text string `json:"text"` // 响应文本
|
||
|
Headers map[string]string `json:"headers"` // 响应头
|
||
|
Cookies map[string]string `json:"cookies"` // todo 添加响应Cookies
|
||
|
Request *Request `json:"request"` // 原始请求
|
||
|
}
|
||
|
|
||
|
// 处理请求方法
|
||
|
func (r *Request) getMethod() string {
|
||
|
return strings.ToUpper(r.Method) // 必须转为全部大写
|
||
|
}
|
||
|
|
||
|
// 组装URL
|
||
|
func (r *Request) getUrl() string {
|
||
|
if r.Params != nil {
|
||
|
urlValues := url.Values{}
|
||
|
Url, _ := url.Parse(r.Url) // todo 处理err
|
||
|
for key, value := range r.Params {
|
||
|
urlValues.Set(key, value)
|
||
|
}
|
||
|
Url.RawQuery = urlValues.Encode()
|
||
|
return Url.String()
|
||
|
}
|
||
|
return r.Url
|
||
|
}
|
||
|
|
||
|
// 组装请求数据
|
||
|
func (r *Request) getData() io.Reader {
|
||
|
var reqBody string
|
||
|
if r.Headers == nil {
|
||
|
r.Headers = make(map[string]string, 1)
|
||
|
}
|
||
|
if r.Raw != "" {
|
||
|
reqBody = r.Raw
|
||
|
} else if r.Data != nil {
|
||
|
urlValues := url.Values{}
|
||
|
for key, value := range r.Data {
|
||
|
urlValues.Add(key, value)
|
||
|
}
|
||
|
reqBody = urlValues.Encode()
|
||
|
r.Headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||
|
} else if r.Json != nil {
|
||
|
bytesData, _ := json.Marshal(r.Json)
|
||
|
reqBody = string(bytesData)
|
||
|
r.Headers["Content-Type"] = "application/json"
|
||
|
} else if r.JsonByte != nil {
|
||
|
reqBody = string(r.JsonByte)
|
||
|
r.Headers["Content-Type"] = "application/json"
|
||
|
}
|
||
|
return strings.NewReader(reqBody)
|
||
|
}
|
||
|
|
||
|
// 添加请求头-需要在getData后使用
|
||
|
func (r *Request) addHeaders(req *http.Request) {
|
||
|
if r.Headers != nil {
|
||
|
for key, value := range r.Headers {
|
||
|
req.Header.Add(key, value)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 准备请求
|
||
|
func (r *Request) prepare() *http.Request {
|
||
|
Method := r.getMethod()
|
||
|
Url := r.getUrl()
|
||
|
Data := r.getData()
|
||
|
req, _ := http.NewRequest(Method, Url, Data)
|
||
|
r.addHeaders(req)
|
||
|
return req
|
||
|
}
|
||
|
|
||
|
// 组装响应对象
|
||
|
func (r *Request) packResponse(res *http.Response, elapsed float64) Response {
|
||
|
var resp Response
|
||
|
resBody, _ := io.ReadAll(res.Body)
|
||
|
resp.Content = resBody
|
||
|
resp.Text = string(resBody)
|
||
|
resp.StatusCode = res.StatusCode
|
||
|
resp.Reason = strings.Split(res.Status, " ")[1]
|
||
|
resp.Elapsed = elapsed
|
||
|
resp.Headers = map[string]string{}
|
||
|
for key, value := range res.Header {
|
||
|
resp.Headers[key] = strings.Join(value, ";")
|
||
|
}
|
||
|
return resp
|
||
|
}
|
||
|
|
||
|
// 发送请求
|
||
|
func (r *Request) Send() (Response, error) {
|
||
|
req := r.prepare()
|
||
|
client := &http.Client{}
|
||
|
start := time.Now()
|
||
|
res, err := client.Do(req)
|
||
|
if err != nil {
|
||
|
return Response{}, err
|
||
|
}
|
||
|
defer res.Body.Close()
|
||
|
elapsed := time.Since(start).Seconds()
|
||
|
return r.packResponse(res, elapsed), nil
|
||
|
}
|