✨ Improve HTTP client function
This commit is contained in:
@@ -23,7 +23,7 @@ type HttpRequest struct {
|
||||
Method string `json:"method"`
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
BodyType string `json:"bodyType,omitempty"` // json, formdata, urlencoded, text
|
||||
BodyType string `json:"bodyType,omitempty"` // json, formdata, urlencoded, text, params, xml, html, javascript, binary
|
||||
Body interface{} `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ func (hcs *HttpClientService) setRequestBody(req *resty.Request, request *HttpRe
|
||||
case "json":
|
||||
req.SetHeader("Content-Type", "application/json")
|
||||
req.SetBody(request.Body)
|
||||
|
||||
case "formdata":
|
||||
if formData, ok := request.Body.(map[string]interface{}); ok {
|
||||
for key, value := range formData {
|
||||
@@ -104,6 +105,7 @@ func (hcs *HttpClientService) setRequestBody(req *resty.Request, request *HttpRe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "urlencoded":
|
||||
req.SetHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
if formData, ok := request.Body.(map[string]interface{}); ok {
|
||||
@@ -113,9 +115,79 @@ func (hcs *HttpClientService) setRequestBody(req *resty.Request, request *HttpRe
|
||||
}
|
||||
req.SetBody(values.Encode())
|
||||
}
|
||||
|
||||
case "text":
|
||||
req.SetHeader("Content-Type", "text/plain")
|
||||
req.SetBody(fmt.Sprintf("%v", request.Body))
|
||||
|
||||
case "params":
|
||||
// URL 参数:添加到查询字符串中
|
||||
if params, ok := request.Body.(map[string]interface{}); ok {
|
||||
for key, value := range params {
|
||||
req.SetQueryParam(key, fmt.Sprintf("%v", value))
|
||||
}
|
||||
}
|
||||
|
||||
case "xml":
|
||||
// XML 格式:从 Body 中提取 xml 字段
|
||||
req.SetHeader("Content-Type", "application/xml")
|
||||
if bodyMap, ok := request.Body.(map[string]interface{}); ok {
|
||||
if xmlContent, exists := bodyMap["xml"]; exists {
|
||||
req.SetBody(fmt.Sprintf("%v", xmlContent))
|
||||
} else {
|
||||
return fmt.Errorf("xml body type requires 'xml' field")
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("xml body must be an object with 'xml' field")
|
||||
}
|
||||
|
||||
case "html":
|
||||
// HTML 格式:从 Body 中提取 html 字段
|
||||
req.SetHeader("Content-Type", "text/html")
|
||||
if bodyMap, ok := request.Body.(map[string]interface{}); ok {
|
||||
if htmlContent, exists := bodyMap["html"]; exists {
|
||||
req.SetBody(fmt.Sprintf("%v", htmlContent))
|
||||
} else {
|
||||
return fmt.Errorf("html body type requires 'html' field")
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("html body must be an object with 'html' field")
|
||||
}
|
||||
|
||||
case "javascript":
|
||||
// JavaScript 格式:从 Body 中提取 javascript 字段
|
||||
req.SetHeader("Content-Type", "application/javascript")
|
||||
if bodyMap, ok := request.Body.(map[string]interface{}); ok {
|
||||
if jsContent, exists := bodyMap["javascript"]; exists {
|
||||
req.SetBody(fmt.Sprintf("%v", jsContent))
|
||||
} else {
|
||||
return fmt.Errorf("javascript body type requires 'javascript' field")
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("javascript body must be an object with 'javascript' field")
|
||||
}
|
||||
|
||||
case "binary":
|
||||
// Binary 格式:从 Body 中提取 binary 字段(文件路径)
|
||||
req.SetHeader("Content-Type", "application/octet-stream")
|
||||
if bodyMap, ok := request.Body.(map[string]interface{}); ok {
|
||||
if binaryContent, exists := bodyMap["binary"]; exists {
|
||||
binaryStr := fmt.Sprintf("%v", binaryContent)
|
||||
// 检查是否是文件类型,使用 @file 关键词
|
||||
if strings.HasPrefix(binaryStr, "@file ") {
|
||||
// 提取文件路径(去掉 @file 前缀)
|
||||
filePath := strings.TrimSpace(strings.TrimPrefix(binaryStr, "@file "))
|
||||
req.SetFile("file", filePath)
|
||||
} else {
|
||||
return fmt.Errorf("binary body requires '@file path/to/file' format")
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("binary body type requires 'binary' field")
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("binary body must be an object with 'binary' field")
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported body type: %s", request.BodyType)
|
||||
}
|
||||
|
||||
212
internal/services/httpclient_service_test.go
Normal file
212
internal/services/httpclient_service_test.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/log"
|
||||
)
|
||||
|
||||
func TestHttpClientService_SetRequestBody(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHttpClientService(logger)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
request *HttpRequest
|
||||
expectError bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "JSON 请求",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/json",
|
||||
BodyType: "json",
|
||||
Body: map[string]interface{}{
|
||||
"name": "张三",
|
||||
"age": 25,
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "XML 请求 - 正确格式",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/xml",
|
||||
BodyType: "xml",
|
||||
Body: map[string]interface{}{
|
||||
"xml": "<user><name>张三</name></user>",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "XML 请求 - 缺少 xml 字段",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/xml",
|
||||
BodyType: "xml",
|
||||
Body: map[string]interface{}{
|
||||
"data": "<user><name>张三</name></user>",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "xml body type requires 'xml' field",
|
||||
},
|
||||
{
|
||||
name: "HTML 请求 - 正确格式",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/html",
|
||||
BodyType: "html",
|
||||
Body: map[string]interface{}{
|
||||
"html": "<div><h1>标题</h1></div>",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "JavaScript 请求 - 正确格式",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/js",
|
||||
BodyType: "javascript",
|
||||
Body: map[string]interface{}{
|
||||
"javascript": "function hello() { return 'world'; }",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Binary 请求 - 正确格式",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/upload",
|
||||
BodyType: "binary",
|
||||
Body: map[string]interface{}{
|
||||
"binary": "@file C:/test.bin",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Binary 请求 - 错误格式(缺少 @file)",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/upload",
|
||||
BodyType: "binary",
|
||||
Body: map[string]interface{}{
|
||||
"binary": "C:/test.bin",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "binary body requires '@file path/to/file' format",
|
||||
},
|
||||
{
|
||||
name: "Params 请求",
|
||||
request: &HttpRequest{
|
||||
Method: "GET",
|
||||
URL: "https://api.example.com/users",
|
||||
BodyType: "params",
|
||||
Body: map[string]interface{}{
|
||||
"page": 1,
|
||||
"size": 20,
|
||||
"query": "test",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "FormData 请求",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/form",
|
||||
BodyType: "formdata",
|
||||
Body: map[string]interface{}{
|
||||
"username": "admin",
|
||||
"password": "123456",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "UrlEncoded 请求",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/login",
|
||||
BodyType: "urlencoded",
|
||||
Body: map[string]interface{}{
|
||||
"username": "admin",
|
||||
"password": "123456",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Text 请求",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/text",
|
||||
BodyType: "text",
|
||||
Body: "纯文本内容",
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "不支持的 Body 类型",
|
||||
request: &HttpRequest{
|
||||
Method: "POST",
|
||||
URL: "https://api.example.com/unknown",
|
||||
BodyType: "unknown",
|
||||
Body: "test",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "unsupported body type: unknown",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req := service.client.R().SetContext(context.Background())
|
||||
err := service.setRequestBody(req, tt.request)
|
||||
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
if tt.errorMsg != "" {
|
||||
assert.Contains(t, err.Error(), tt.errorMsg)
|
||||
}
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpClientService_FormatBytes(t *testing.T) {
|
||||
logger := log.New()
|
||||
service := NewHttpClientService(logger)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
bytes int64
|
||||
expected string
|
||||
}{
|
||||
{"负数", -1, "0 B"},
|
||||
{"零字节", 0, "0 B"},
|
||||
{"小于1KB", 500, "500 B"},
|
||||
{"1KB", 1024, "1.0 KB"},
|
||||
{"1MB", 1024 * 1024, "1.0 MB"},
|
||||
{"1.5MB", 1024*1024 + 512*1024, "1.5 MB"},
|
||||
{"1GB", 1024 * 1024 * 1024, "1.0 GB"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := service.formatBytes(tt.bytes)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user