Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
2bd8cf162f | |||
8c5228668f | |||
1549e4142c | |||
7fe8681468 | |||
2c28809b1e | |||
fe2cdb4f21 | |||
249e749e6c | |||
c9f818da64 | |||
36145caa65 | |||
0ec26e5721 | |||
1af2896025 |
37
README.MD
37
README.MD
@ -1,10 +1,11 @@
|
|||||||
_# simpleRequest
|
# simpleRequest
|
||||||
## 1. 说明
|
## 1. 说明
|
||||||
[simpleRequest](www.github.com/dorlolo/simpleRequest) 是一款面向对象开发的http请求库。他是基于Go原生http库。开发这个模块的主要目的是为了更快的对接第三方api接口。
|
[simpleRequest](www.github.com/dorlolo/simpleRequest) 是一款面向对象的http请求库,它在Go原生的http库为基础做了一定的封装,使开发更加便捷。
|
||||||
它具备以下特点:
|
|
||||||
- 极简化的代码,大大提高了代码编写速度。
|
> [simpleRequest](www.github.com/dorlolo/simpleRequest) 具备以下特点:
|
||||||
- 更易于理解和使用,减少了资料查询的时间。
|
- 没有在代码层面遵循restful规范,适合对接不符合规范的接口;
|
||||||
- 更适合对接一些不遵循restful规范的接口。
|
- 轻量级、不需要繁琐的配置;
|
||||||
|
- 易于理解和使用,减少了资料查询的时间。
|
||||||
|
|
||||||
这是它的一个示例:
|
这是它的一个示例:
|
||||||
```go
|
```go
|
||||||
@ -61,12 +62,13 @@ r.Headers().Set("token", "d+jfdji*D%1=").Set("Content-Type", "application/json")
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### 2.4.4 添加多值
|
#### 2.4.4 添加多值
|
||||||
对单个key添加多只不要使用`.set`,因为原先的值会被覆盖
|
|
||||||
```go
|
```go
|
||||||
|
// 对相同key的值进行覆盖,请使用Set方法
|
||||||
r.Headers().Set("Accept", "text/html")
|
r.Headers().Set("Accept", "text/html")
|
||||||
|
// 对相同key的值进行追加,请使用Add方法
|
||||||
r.Headers().Add("Accept","application/xhtml+xml")
|
r.Headers().Add("Accept","application/xhtml+xml")
|
||||||
r.Headers().Add("Accept","application/xml;q=0.8")
|
r.Headers().Add("Accept","application/xml;q=0.8")
|
||||||
r.Headers().Add("Accept","image/webp")
|
|
||||||
r.Headers().Add("Accept","*/*;q=0.8")
|
r.Headers().Add("Accept","*/*;q=0.8")
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -101,6 +103,16 @@ r.Headers().ConentType_textPlain()
|
|||||||
//r.Headers().Set("Content-Type","text/plain; charset=utf-8")
|
//r.Headers().Set("Content-Type","text/plain; charset=utf-8")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 2.4.5 忽略指定请求头/禁用默认content-Type
|
||||||
|
在默认情况下,`Content-Type`将被自动添加到请求头中,值为`application/x-www-form-urlencoded`。但对于某些场景来说这会导致请求失败。使用下面的方法可以忽略指定的请求头
|
||||||
|
```go
|
||||||
|
r.Headers().Omit("Content-Type")
|
||||||
|
```
|
||||||
|
或者使用以下方法禁用**默认content-Type**。禁用后当你不主动设置`Content-Type`时,请求头中将不会包含`Content-Type`。
|
||||||
|
```go
|
||||||
|
var r = simpleRequest.NewRequest(simpleRequest.OptionDisableDefaultContentType())
|
||||||
|
````
|
||||||
|
|
||||||
### 2.5 添加queryParams
|
### 2.5 添加queryParams
|
||||||
#### 2.5.1 单个赋值
|
#### 2.5.1 单个赋值
|
||||||
```go
|
```go
|
||||||
@ -231,7 +243,7 @@ func FileForwardUseBytesBody(c *gin.Context){
|
|||||||
writer = multipart.NewWriter(body)
|
writer = multipart.NewWriter(body)
|
||||||
)
|
)
|
||||||
// add file object
|
// add file object
|
||||||
filePart, _ := i.writer.CreateFormFile("file", file.Filename)
|
filePart, _ := writer.CreateFormFile("file", file.Filename)
|
||||||
src, err := file.Open()
|
src, err := file.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println( err.Error())
|
fmt.Println( err.Error())
|
||||||
@ -305,11 +317,14 @@ if err != nil {
|
|||||||
```go
|
```go
|
||||||
requestContext:=r.Request
|
requestContext:=r.Request
|
||||||
```
|
```
|
||||||
|
为了让用户能够便于分析调试,在进行http请求后r.Request.Body中的数据仍旧可读,但是会丧失部分性能,如果要禁用此功能请使用以下方法。
|
||||||
|
```go
|
||||||
|
var r = simpleRequest.NewRequest(simpleRequest.OptionDisableDefaultContentType())
|
||||||
|
```
|
||||||
#### 2.10.2 获取返回的上下文对象
|
#### 2.10.2 获取返回的上下文对象
|
||||||
```go
|
```go
|
||||||
responseContext:=r.Response
|
responseContext:=r.Response
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. 使用示例
|
## 3. 使用示例
|
||||||
[simpleRequest_test.go](excample/simpleRequest_test.go)_
|
[simpleRequest_test.go](excample/simpleRequest_test.go)
|
32
body.go
32
body.go
@ -7,7 +7,12 @@
|
|||||||
|
|
||||||
package simpleRequest
|
package simpleRequest
|
||||||
|
|
||||||
import "mime/multipart"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// EntryMark 请求体条目标记,用于标记输入的body内容格式
|
// EntryMark 请求体条目标记,用于标记输入的body内容格式
|
||||||
type EntryMark string
|
type EntryMark string
|
||||||
@ -25,6 +30,21 @@ const (
|
|||||||
FormFilePathKey EntryMark = "__FORM_FILE_PATH_KEY__"
|
FormFilePathKey EntryMark = "__FORM_FILE_PATH_KEY__"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetStringEntryTypeBody(bodyEntries map[string]any) io.Reader {
|
||||||
|
data, ok := bodyEntries[StringEntryType.string()]
|
||||||
|
if !ok || data == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strings.NewReader(data.(string))
|
||||||
|
}
|
||||||
|
func GetBytesEntryTypeBody(bodyEntries map[string]any) io.Reader {
|
||||||
|
data, ok := bodyEntries[BytesEntryType.string()]
|
||||||
|
if !ok || data == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return bytes.NewReader(data.([]byte))
|
||||||
|
}
|
||||||
|
|
||||||
type BodyConf struct {
|
type BodyConf struct {
|
||||||
simpleReq *SimpleRequest
|
simpleReq *SimpleRequest
|
||||||
}
|
}
|
||||||
@ -57,13 +77,23 @@ func (s *BodyConf) SetModel(model any) *BodyConf {
|
|||||||
s.simpleReq.BodyEntries[ModelEntryType.string()] = model
|
s.simpleReq.BodyEntries[ModelEntryType.string()] = model
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加上传文件
|
||||||
func (s *BodyConf) SetFromDataFile(key, filePath string) *BodyConf {
|
func (s *BodyConf) SetFromDataFile(key, filePath string) *BodyConf {
|
||||||
s.simpleReq.BodyEntryMark = MultipartEntryType
|
s.simpleReq.BodyEntryMark = MultipartEntryType
|
||||||
s.simpleReq.BodyEntries[FormFilePathKey.string()+key] = filePath
|
s.simpleReq.BodyEntries[FormFilePathKey.string()+key] = filePath
|
||||||
|
if s.simpleReq.headers.Get(hdrContentTypeKey) == "" {
|
||||||
|
s.simpleReq.headers.Set(hdrContentTypeKey, formDataType)
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加文件,适用于服务端文件转发场景,比如直接从c.FormFile("file")中获取FileHeader对象转发即可
|
||||||
func (s *BodyConf) SetFromDataMultipartFile(key string, multFile *multipart.FileHeader) *BodyConf {
|
func (s *BodyConf) SetFromDataMultipartFile(key string, multFile *multipart.FileHeader) *BodyConf {
|
||||||
s.simpleReq.BodyEntryMark = MultipartEntryType
|
s.simpleReq.BodyEntryMark = MultipartEntryType
|
||||||
s.simpleReq.BodyEntries[key] = multFile
|
s.simpleReq.BodyEntries[key] = multFile
|
||||||
|
if s.simpleReq.headers.Get(hdrContentTypeKey) == "" {
|
||||||
|
s.simpleReq.headers.Set(hdrContentTypeKey, formDataType)
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dorlolo/simpleRequest"
|
"github.com/dorlolo/simpleRequest"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -50,7 +51,7 @@ func TestRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 测试content-type 为 multipart/form-data格式的数据请求
|
// 测试content-type 为 multipart/form-data格式的数据请求
|
||||||
func TestAuth_fotmData(t *testing.T) {
|
func TestAuth_formData(t *testing.T) {
|
||||||
req := simpleRequest.NewRequest()
|
req := simpleRequest.NewRequest()
|
||||||
req.Headers().ConentType_formData()
|
req.Headers().ConentType_formData()
|
||||||
req.Headers().SetRandomUerAgent()
|
req.Headers().SetRandomUerAgent()
|
||||||
@ -132,3 +133,24 @@ func TestTextPlain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 阿里云Oss文件上传示例
|
||||||
|
func TestUploadFileToOss(t *testing.T) {
|
||||||
|
var signedUrl = "" //STS授权url
|
||||||
|
var xOssCallback = "" //回调信息
|
||||||
|
var req = simpleRequest.NewRequest()
|
||||||
|
req.Headers().
|
||||||
|
Sets(map[string]string{
|
||||||
|
"X-Oss-Callback": xOssCallback,
|
||||||
|
})
|
||||||
|
|
||||||
|
fileData, err := os.ReadFile("./CHANGELOG.MD")
|
||||||
|
req.Body().SetBytes(fileData)
|
||||||
|
|
||||||
|
body, err := req.PUT(signedUrl)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(body))
|
||||||
|
}
|
||||||
|
@ -69,7 +69,7 @@ func (s *HeadersConf) Omit(keys ...string) *HeadersConf {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
//一般用不到
|
//deprecated
|
||||||
//func (s *HeadersConf) Values(keys string) *HeadersConf {
|
//func (s *HeadersConf) Values(keys string) *HeadersConf {
|
||||||
// s.simpleReq.headers.Values(keys)
|
// s.simpleReq.headers.Values(keys)
|
||||||
// return s
|
// return s
|
||||||
|
17
options.go
17
options.go
@ -15,3 +15,20 @@ func OptionNewBodyEntryParser(contentType string, parser IBodyEntryParser) OPTIO
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionDisableDefaultContentType 禁用默认的ContentType
|
||||||
|
// 当未指定ContentType时,将不会使用默认的ContentType
|
||||||
|
func OptionDisableDefaultContentType() OPTION {
|
||||||
|
return func(r *SimpleRequest) *SimpleRequest {
|
||||||
|
r.disableDefaultContentType = true
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionDisableCopyRequestBody 禁用复制RequestBody
|
||||||
|
func OptionDisableCopyRequestBody() OPTION {
|
||||||
|
return func(r *SimpleRequest) *SimpleRequest {
|
||||||
|
r.disableCopyRequestBody = true
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
49
options_test.go
Normal file
49
options_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Package simpleRequest -----------------------------
|
||||||
|
// @file : options_test.go
|
||||||
|
// @author : JJXu
|
||||||
|
// @contact : wavingbear@163.com
|
||||||
|
// @time : 2024/1/12 11:27
|
||||||
|
// -------------------------------------------
|
||||||
|
package simpleRequest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOptionDisableDefaultContentType(t *testing.T) {
|
||||||
|
go httpserver()
|
||||||
|
var r = NewRequest(OptionDisableDefaultContentType())
|
||||||
|
r.Headers()
|
||||||
|
bodyData := "{'a'=123,'b'=56}"
|
||||||
|
r.Body().SetString(bodyData)
|
||||||
|
_, err := r.POST("http://localhost:8989")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Request.Header.Get(hdrContentTypeKey) != "" {
|
||||||
|
t.Errorf("query params want '%s' but get '%s'", "", r.Request.Header.Get(hdrContentTypeKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOptionOptionDisableCopyRequestBody(t *testing.T) {
|
||||||
|
go httpserver()
|
||||||
|
var r = NewRequest(OptionDisableCopyRequestBody())
|
||||||
|
r.Headers()
|
||||||
|
bodyData := "{'a'=123,'b'=56}"
|
||||||
|
r.Body().SetString(bodyData)
|
||||||
|
_, err := r.POST("http://localhost:8989")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(r.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if string(body) != "" {
|
||||||
|
t.Errorf("query params want '%s' but get '%s'", "", body)
|
||||||
|
}
|
||||||
|
}
|
63
parser.go
63
parser.go
@ -9,17 +9,21 @@ package simpleRequest
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 通用类型解析器
|
||||||
var bodyEntryParsers = map[string]IBodyEntryParser{
|
var bodyEntryParsers = map[string]IBodyEntryParser{
|
||||||
jsonContentType: new(JsonParser),
|
jsonContentType: new(JsonParser),
|
||||||
formDataType: new(FormDataParser),
|
formDataType: new(FormDataParser),
|
||||||
|
xmlDataType: new(XmlParser),
|
||||||
}
|
}
|
||||||
|
|
||||||
type IBodyEntryParser interface {
|
type IBodyEntryParser interface {
|
||||||
@ -31,9 +35,9 @@ type JsonParser struct{}
|
|||||||
func (JsonParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) io.Reader {
|
func (JsonParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) io.Reader {
|
||||||
switch bodyType {
|
switch bodyType {
|
||||||
case StringEntryType:
|
case StringEntryType:
|
||||||
return strings.NewReader(BodyEntry[StringEntryType.string()].(string))
|
return GetStringEntryTypeBody(BodyEntry)
|
||||||
case BytesEntryType:
|
case BytesEntryType:
|
||||||
return bytes.NewReader(BodyEntry[BytesEntryType.string()].([]byte))
|
return GetBytesEntryTypeBody(BodyEntry)
|
||||||
case ModelEntryType:
|
case ModelEntryType:
|
||||||
jsonData, err := json.Marshal(BodyEntry[ModelEntryType.string()])
|
jsonData, err := json.Marshal(BodyEntry[ModelEntryType.string()])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -79,9 +83,9 @@ func (f *FormDataParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any)
|
|||||||
}
|
}
|
||||||
body, f.ContentType = multipartCommonParse(mapper)
|
body, f.ContentType = multipartCommonParse(mapper)
|
||||||
case StringEntryType:
|
case StringEntryType:
|
||||||
return strings.NewReader(BodyEntry[StringEntryType.string()].(string))
|
return GetStringEntryTypeBody(BodyEntry)
|
||||||
case BytesEntryType:
|
case BytesEntryType:
|
||||||
return bytes.NewReader(BodyEntry[BytesEntryType.string()].([]byte))
|
return GetBytesEntryTypeBody(BodyEntry)
|
||||||
default:
|
default:
|
||||||
body, f.ContentType = multipartCommonParse(BodyEntry)
|
body, f.ContentType = multipartCommonParse(BodyEntry)
|
||||||
}
|
}
|
||||||
@ -138,3 +142,54 @@ func multipartCommonParse(BodyEntry map[string]any) (reader io.Reader, contentTy
|
|||||||
}
|
}
|
||||||
return body, formWriter.FormDataContentType()
|
return body, formWriter.FormDataContentType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type XmlParser struct{}
|
||||||
|
|
||||||
|
func (f XmlParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) (body io.Reader) {
|
||||||
|
switch bodyType {
|
||||||
|
case MapEntryType:
|
||||||
|
xmlData, err := xml.Marshal(BodyEntry[bodyType.string()])
|
||||||
|
if err == nil {
|
||||||
|
return bytes.NewReader(xmlData)
|
||||||
|
} else {
|
||||||
|
return strings.NewReader("")
|
||||||
|
}
|
||||||
|
case ModelEntryType:
|
||||||
|
xmlData, err := xml.Marshal(BodyEntry[bodyType.string()])
|
||||||
|
if err == nil {
|
||||||
|
return bytes.NewReader(xmlData)
|
||||||
|
} else {
|
||||||
|
return strings.NewReader("")
|
||||||
|
}
|
||||||
|
case StringEntryType:
|
||||||
|
return GetStringEntryTypeBody(BodyEntry)
|
||||||
|
case BytesEntryType:
|
||||||
|
return GetBytesEntryTypeBody(BodyEntry)
|
||||||
|
default:
|
||||||
|
return strings.NewReader("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommonParser struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f CommonParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) (body io.Reader) {
|
||||||
|
tmpData := url.Values{}
|
||||||
|
for k, v := range BodyEntry {
|
||||||
|
switch k {
|
||||||
|
case StringEntryType.string():
|
||||||
|
body = GetStringEntryTypeBody(BodyEntry)
|
||||||
|
break
|
||||||
|
case BytesEntryType.string():
|
||||||
|
body = GetBytesEntryTypeBody(BodyEntry)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if strings.HasPrefix(k, FormFilePathKey.string()) {
|
||||||
|
k = k[len(FormFilePathKey):]
|
||||||
|
}
|
||||||
|
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body = strings.NewReader(tmpData.Encode())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
118
parser_test.go
Normal file
118
parser_test.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Package simpleRequest -----------------------------
|
||||||
|
// @file : parser_test.go
|
||||||
|
// @author : JJXu
|
||||||
|
// @contact : wavingbear@163.com
|
||||||
|
// @time : 2024/1/11 18:35
|
||||||
|
// -------------------------------------------
|
||||||
|
package simpleRequest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormDataParser_Unmarshal(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
ContentType string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
bodyType EntryMark
|
||||||
|
BodyEntry map[string]any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantBody io.Reader
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "StringEntryType",
|
||||||
|
fields: fields{},
|
||||||
|
args: args{
|
||||||
|
bodyType: StringEntryType,
|
||||||
|
BodyEntry: map[string]any{StringEntryType.string(): "test"},
|
||||||
|
},
|
||||||
|
wantBody: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f := &FormDataParser{
|
||||||
|
ContentType: tt.fields.ContentType,
|
||||||
|
}
|
||||||
|
if gotBody := f.Unmarshal(tt.args.bodyType, tt.args.BodyEntry); !reflect.DeepEqual(gotBody, tt.wantBody) {
|
||||||
|
t.Errorf("Unmarshal() = %v, want %v", gotBody, tt.wantBody)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJsonParser_Unmarshal(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
bodyType EntryMark
|
||||||
|
BodyEntry map[string]any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want io.Reader
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
js := JsonParser{}
|
||||||
|
if got := js.Unmarshal(tt.args.bodyType, tt.args.BodyEntry); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Unmarshal() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXmlParser_Unmarshal(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
bodyType EntryMark
|
||||||
|
BodyEntry map[string]any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantBody io.Reader
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f := XmlParser{}
|
||||||
|
if gotBody := f.Unmarshal(tt.args.bodyType, tt.args.BodyEntry); !reflect.DeepEqual(gotBody, tt.wantBody) {
|
||||||
|
t.Errorf("Unmarshal() = %v, want %v", gotBody, tt.wantBody)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multipartCommonParse(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
BodyEntry map[string]any
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantReader io.Reader
|
||||||
|
wantContentType string
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotReader, gotContentType := multipartCommonParse(tt.args.BodyEntry)
|
||||||
|
if !reflect.DeepEqual(gotReader, tt.wantReader) {
|
||||||
|
t.Errorf("multipartCommonParse() gotReader = %v, want %v", gotReader, tt.wantReader)
|
||||||
|
}
|
||||||
|
if gotContentType != tt.wantContentType {
|
||||||
|
t.Errorf("multipartCommonParse() gotContentType = %v, want %v", gotContentType, tt.wantContentType)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
204
simpleRequest.go
204
simpleRequest.go
@ -8,7 +8,9 @@
|
|||||||
package simpleRequest
|
package simpleRequest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -48,14 +50,16 @@ type SimpleRequest struct {
|
|||||||
omitHeaderKeys []string
|
omitHeaderKeys []string
|
||||||
transport *http.Transport
|
transport *http.Transport
|
||||||
|
|
||||||
BodyEntryMark EntryMark
|
BodyEntryMark EntryMark // 用于标记输入的body内容格式
|
||||||
BodyEntries map[string]any
|
BodyEntries map[string]any // 输入的body中的内容
|
||||||
bodyEntryParsers map[string]IBodyEntryParser
|
bodyEntryParsers map[string]IBodyEntryParser // 用于将BodyEntries中的内容解析后传入request body中
|
||||||
|
disableDefaultContentType bool // 禁用默认的ContentType
|
||||||
|
disableCopyRequestBody bool // 禁用复制请求体,在进行http请求后SimpleRequest.Request.Body中内容会无法读取,但是会提高性能
|
||||||
|
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
Response http.Response //用于获取完整的返回内容。请注意要在请求之后才能获取
|
Response *http.Response //用于获取完整的返回内容。请注意要在请求之后才能获取
|
||||||
Request http.Request //用于获取完整的请求内容。请注意要在请求之后才能获取
|
Request *http.Request //用于获取完整的请求内容。请注意要在请求之后才能获取
|
||||||
//cookies map[string]string
|
//cookies map[string]string
|
||||||
//data any
|
//data any
|
||||||
//cli *http.Client
|
//cli *http.Client
|
||||||
@ -143,23 +147,17 @@ func (s *SimpleRequest) do(request *http.Request) (body []byte, err error) {
|
|||||||
//3.1 发送数据
|
//3.1 发送数据
|
||||||
resp, err := client.Do(request)
|
resp, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("【Request Error】:", err.Error())
|
err = errors.New("[client.Do Err]:" + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//v0.0.2更新,将request和response内容返回,便于用户进行分析 JJXu 03-11-2022
|
//v0.0.2更新,将request和response内容返回,便于用户进行分析 JJXu 03-11-2022
|
||||||
|
s.Request = request
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
s.Response = *resp
|
s.Response = resp
|
||||||
} else {
|
defer resp.Body.Close()
|
||||||
return
|
body, err = io.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
if request != nil {
|
|
||||||
s.Request = *request
|
|
||||||
}
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
//3.2 获取数据
|
|
||||||
body, err = io.ReadAll(resp.Body)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,17 +173,32 @@ func (s *SimpleRequest) GET(urls string) (body []byte, err error) {
|
|||||||
|
|
||||||
// 通用的请求方法
|
// 通用的请求方法
|
||||||
func (s *SimpleRequest) LaunchTo(urls, method string) (body []byte, err error) {
|
func (s *SimpleRequest) LaunchTo(urls, method string) (body []byte, err error) {
|
||||||
|
var r *http.Request
|
||||||
// body
|
// body
|
||||||
s.initBody()
|
s.initBody()
|
||||||
r, err := http.NewRequest(method, urls, s.body)
|
var copBody []byte
|
||||||
if err != nil {
|
if s.body != nil {
|
||||||
return nil, err
|
copBody, err = io.ReadAll(s.body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !s.disableCopyRequestBody {
|
||||||
|
// 使r.body在请求后仍旧可读,便于使用者对请求过程进行分析
|
||||||
|
r, err = http.NewRequest(method, urls, io.NopCloser(bytes.NewBuffer(copBody)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
r.Body = io.NopCloser(bytes.NewBuffer(copBody))
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
r, err = http.NewRequest(method, urls, s.body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//headers
|
//headers
|
||||||
//for k := range s.headers {
|
|
||||||
// r.Header[k] = append(r.Header[k], s.headers[k]...)
|
|
||||||
// s.headers.Del(k)
|
|
||||||
//}
|
|
||||||
r.Header = s.headers
|
r.Header = s.headers
|
||||||
for _, k := range s.omitHeaderKeys {
|
for _, k := range s.omitHeaderKeys {
|
||||||
r.Header.Del(k)
|
r.Header.Del(k)
|
||||||
@ -247,64 +260,101 @@ func (s *SimpleRequest) TRACE(url string) (body []byte, err error) {
|
|||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
//
|
//
|
||||||
// 这里数据
|
// Automatically parses the request body based on the content-type type defined in the request header
|
||||||
func (s *SimpleRequest) initBody() {
|
func (s *SimpleRequest) initBody() {
|
||||||
contentTypeData := s.headers.Get(hdrContentTypeKey)
|
contentTypeData := s.headers.Get(hdrContentTypeKey)
|
||||||
switch {
|
if contentTypeData != "" {
|
||||||
case IsJSONType(contentTypeData):
|
switch {
|
||||||
var parser, ok = s.bodyEntryParsers[jsonContentType]
|
case IsJSONType(contentTypeData):
|
||||||
if !ok {
|
var parser, ok = s.bodyEntryParsers[jsonContentType]
|
||||||
parser = new(JsonParser)
|
if !ok {
|
||||||
}
|
parser = new(JsonParser)
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
|
||||||
|
|
||||||
case strings.Contains(contentTypeData, formDataType):
|
|
||||||
var parser, ok = s.bodyEntryParsers[formDataType]
|
|
||||||
if !ok {
|
|
||||||
parser = new(FormDataParser)
|
|
||||||
}
|
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
|
||||||
fdParser := parser.(*FormDataParser)
|
|
||||||
s.headers.Set("Content-Type", fdParser.ContentType)
|
|
||||||
|
|
||||||
case IsXMLType(contentTypeData):
|
|
||||||
//application/soap+xml ,application/xml
|
|
||||||
var parser, ok = s.bodyEntryParsers[xmlDataType]
|
|
||||||
if !ok {
|
|
||||||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
|
||||||
s.body = strings.NewReader(data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
|
||||||
|
|
||||||
case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType):
|
|
||||||
var parser, ok = s.bodyEntryParsers[textPlainType]
|
|
||||||
if !ok {
|
|
||||||
data, _ := s.BodyEntries[StringEntryType.string()].(string)
|
|
||||||
s.body = strings.NewReader(data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
|
||||||
|
|
||||||
case contentTypeData == "" || strings.Contains(contentTypeData, "form-urlencoded"):
|
|
||||||
//default header type is "x-www-form-urlencoded"
|
|
||||||
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
|
||||||
if !ok {
|
|
||||||
tmpData := url.Values{}
|
|
||||||
for k, v := range s.BodyEntries {
|
|
||||||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
|
||||||
}
|
}
|
||||||
s.body = strings.NewReader(tmpData.Encode())
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
s.Headers().ConentType_formUrlencoded()
|
|
||||||
return
|
case strings.Contains(contentTypeData, formDataType):
|
||||||
|
var parser, ok = s.bodyEntryParsers[formDataType]
|
||||||
|
if !ok {
|
||||||
|
parser = new(FormDataParser)
|
||||||
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
fdParser := parser.(*FormDataParser)
|
||||||
|
s.headers.Set("Content-Type", fdParser.ContentType)
|
||||||
|
|
||||||
|
case IsXMLType(contentTypeData):
|
||||||
|
//application/soap+xml ,application/xml
|
||||||
|
var parser, ok = s.bodyEntryParsers[xmlDataType]
|
||||||
|
if !ok {
|
||||||
|
s.body = GetStringEntryTypeBody(s.BodyEntries)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
|
||||||
|
case strings.Contains(contentTypeData, "text") || strings.Contains(contentTypeData, javaScriptType):
|
||||||
|
var parser, ok = s.bodyEntryParsers[textPlainType]
|
||||||
|
if !ok {
|
||||||
|
s.body = GetStringEntryTypeBody(s.BodyEntries)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
|
||||||
|
case strings.Contains(contentTypeData, "form-urlencoded"):
|
||||||
|
//default header type is "x-www-form-urlencoded"
|
||||||
|
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
||||||
|
if !ok {
|
||||||
|
for k, v := range s.BodyEntries {
|
||||||
|
if v == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case StringEntryType.string():
|
||||||
|
s.body = GetStringEntryTypeBody(s.BodyEntries)
|
||||||
|
break
|
||||||
|
case BytesEntryType.string():
|
||||||
|
s.body = GetBytesEntryTypeBody(s.BodyEntries)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
tmpData := url.Values{}
|
||||||
|
if strings.HasPrefix(k, FormFilePathKey.string()) {
|
||||||
|
k = k[len(FormFilePathKey):]
|
||||||
|
}
|
||||||
|
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||||||
|
s.body = strings.NewReader(tmpData.Encode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//s.Headers().ConentType_formUrlencoded()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
|
default:
|
||||||
|
// 自动处理body数据
|
||||||
|
s.body = new(CommonParser).Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
}
|
}
|
||||||
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
} else {
|
||||||
default:
|
switch s.BodyEntryMark {
|
||||||
//todo Automatically determine the data type
|
case BytesEntryType:
|
||||||
tmpData := url.Values{}
|
s.body = GetBytesEntryTypeBody(s.BodyEntries)
|
||||||
for k, v := range tmpData {
|
case StringEntryType:
|
||||||
tmpData.Set(k, fmt.Sprintf("%v", v))
|
s.body = GetStringEntryTypeBody(s.BodyEntries)
|
||||||
|
default:
|
||||||
|
var parser, ok = s.bodyEntryParsers["form-urlencoded"]
|
||||||
|
if !ok {
|
||||||
|
tmpData := url.Values{}
|
||||||
|
for k, v := range s.BodyEntries {
|
||||||
|
if strings.HasPrefix(k, FormFilePathKey.string()) {
|
||||||
|
k = k[len(FormFilePathKey):]
|
||||||
|
}
|
||||||
|
tmpData.Set(k, fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
s.body = strings.NewReader(tmpData.Encode())
|
||||||
|
if !s.disableDefaultContentType {
|
||||||
|
s.Headers().ConentType_formUrlencoded()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.body = parser.Unmarshal(s.BodyEntryMark, s.BodyEntries)
|
||||||
}
|
}
|
||||||
s.body = strings.NewReader(tmpData.Encode())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ package simpleRequest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
@ -35,7 +34,7 @@ func httpserver() {
|
|||||||
io.WriteString(w, "false")
|
io.WriteString(w, "false")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
fmt.Println("http服务启动了")
|
//fmt.Println("http服务启动了")
|
||||||
http.ListenAndServe(":8989", nil)
|
http.ListenAndServe(":8989", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +97,64 @@ func TestQueryUrl2(t *testing.T) {
|
|||||||
t.Error(err.Error())
|
t.Error(err.Error())
|
||||||
} else {
|
} else {
|
||||||
if r.Request.URL.RawQuery != "a=123&b=456&c=3" {
|
if r.Request.URL.RawQuery != "a=123&b=456&c=3" {
|
||||||
t.Errorf("query params wangt '%s' but get '%s'", "a=123&b=456&c=3", r.Request.URL.RawQuery)
|
t.Errorf("query params want '%s' but get '%s'", "a=123&b=456&c=3", r.Request.URL.RawQuery)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 请求后,r.Request.Body中的内容仍旧可读
|
||||||
|
func TestQueryUseStringBody(t *testing.T) {
|
||||||
|
go httpserver()
|
||||||
|
var r = NewRequest()
|
||||||
|
r.Headers().ConentType_json()
|
||||||
|
bodyData := "{'a'=123,'b'=56}"
|
||||||
|
r.Body().SetString(bodyData)
|
||||||
|
_, err := r.POST("http://localhost:8989")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(r.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if string(body) != bodyData {
|
||||||
|
t.Errorf("request body want '%s' but get '%s'", bodyData, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyBody(t *testing.T) {
|
||||||
|
go httpserver()
|
||||||
|
var r = NewRequest()
|
||||||
|
r.Headers().ConentType_json()
|
||||||
|
_, err := r.POST("http://localhost:8989")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(r.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if string(body) != "{}" {
|
||||||
|
t.Errorf("request body want '%s' but get '%s'", "{}", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Headers().ConentType_formUrlencoded()
|
||||||
|
_, err = r.POST("http://localhost:8989")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err = io.ReadAll(r.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if string(body) != "" {
|
||||||
|
t.Errorf("request body want '%s' but get '%s'", "", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
86
utils.go
86
utils.go
@ -7,6 +7,11 @@
|
|||||||
|
|
||||||
package simpleRequest
|
package simpleRequest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
func IsJSONType(ct string) bool {
|
func IsJSONType(ct string) bool {
|
||||||
return jsonCheck.MatchString(ct)
|
return jsonCheck.MatchString(ct)
|
||||||
}
|
}
|
||||||
@ -24,3 +29,84 @@ func IsInArray(arr []string, str string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type xmlMapEntry struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
Value interface{} `xml:",chardata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// func MapToXml(data map[string]any) ([]byte, error) {
|
||||||
|
// xmlData, err := mapToXML(data)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// return xml.MarshalIndent(xmlData, "", " ")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func mapToXML(m map[string]interface{}) (xmlMap map[string]xmlMapEntry, err error) {
|
||||||
|
// if len(m) > 1 {
|
||||||
|
// return nil, errors.New("xml format must have a root name,the map value must like this: map[string]interface{}{\"rootName\":map[string]interface{}{}}")
|
||||||
|
// }
|
||||||
|
// xmlMap = make(map[string]xmlMapEntry)
|
||||||
|
// var rootName string
|
||||||
|
// for root, data := range m {
|
||||||
|
// rootName = root
|
||||||
|
// for k, v := range data.(map[string]interface{}) {
|
||||||
|
// switch typeV := v.(type) {
|
||||||
|
// case map[string]interface{}:
|
||||||
|
// subXmlMap, err := mapToXML(typeV)
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// entry := xmlMapEntry{XMLName: xml.Name{Local: k}, Value: v}
|
||||||
|
// xmlMap[k] = entry
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// xmlData := struct {
|
||||||
|
// XMLName xml.Name
|
||||||
|
// Data []xmlMapEntry `xml:",any"`
|
||||||
|
// }{
|
||||||
|
// XMLName: xml.Name{Local: rootName},
|
||||||
|
// Data: make([]xmlMapEntry, 0, len(xmlMap)),
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for _, v := range xmlMap {
|
||||||
|
// xmlData.Data = append(xmlData.Data, v)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return xml.MarshalIndent(xmlData, "", " ")
|
||||||
|
// }
|
||||||
|
|
||||||
|
func mapToXML(m map[string]interface{}) ([]byte, error) {
|
||||||
|
xmlData := make([]xmlNode, 0)
|
||||||
|
|
||||||
|
for k, v := range m {
|
||||||
|
node := xmlNode{
|
||||||
|
XMLName: xml.Name{Local: k},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := v.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
childXML, err := mapToXML(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
node.Data = childXML
|
||||||
|
default:
|
||||||
|
node.Data = []byte(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlData = append(xmlData, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return xml.MarshalIndent(xmlData, "", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
type xmlNode struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
Data []byte `xml:",innerxml"`
|
||||||
|
}
|
||||||
|
82
utils_test.go
Normal file
82
utils_test.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Package simpleRequest -----------------------------
|
||||||
|
// @file : utils_test.go
|
||||||
|
// @author : JJXu
|
||||||
|
// @contact : wavingbear@163.com
|
||||||
|
// @time : 2023/11/17 16:37
|
||||||
|
// -------------------------------------------
|
||||||
|
package simpleRequest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_mapToXML(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
m map[string]interface{}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "多级xml测试",
|
||||||
|
args: args{
|
||||||
|
m: map[string]interface{}{
|
||||||
|
"UserInfo": map[string]any{
|
||||||
|
"Name": "JJXu",
|
||||||
|
"Age": 18,
|
||||||
|
"isTrueMan": true,
|
||||||
|
"assets": map[string]any{
|
||||||
|
"car": "BMW",
|
||||||
|
"house": "shanghai",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: "<UserInfo>\n<Age>18</Age>\n<isTrueMan>true</isTrueMan>\n<assets></assets>\n<Name>JJXu</Name>\n</UserInfo>",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "错误格式测试",
|
||||||
|
args: args{},
|
||||||
|
want: "",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := mapToXML(tt.args.m)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("mapToXML() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if string(got) != tt.want {
|
||||||
|
t.Errorf("mapToXML() got = %v, want %v", string(got), tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func Test_mapToXML2(t *testing.T) {
|
||||||
|
person := map[string]interface{}{
|
||||||
|
"userInfo": map[string]interface{}{
|
||||||
|
"name": "John",
|
||||||
|
"age": 30,
|
||||||
|
"address": map[string]interface{}{
|
||||||
|
"street": "123 Main St",
|
||||||
|
"city": "New York",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlBytes, err := mapToXML(person)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlString := string(xmlBytes)
|
||||||
|
fmt.Println(xmlString)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user