From 5c2d74c51d29a88a8e3125187767210849483afc Mon Sep 17 00:00:00 2001 From: jjxu <428192774@qq.com> Date: Wed, 21 Jun 2023 16:23:10 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8Dformdata=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=95=B0=E6=8D=AE=E8=AF=B7=E6=B1=82=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=202.=20=E6=96=B0=E5=A2=9E=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=96=87=E4=BB=B6=E7=9A=84=E5=86=85=E7=BD=AE=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 104 +++++++++++++++++++++++++++++++++++++++++++++++++----- body.go | 22 +++++++++--- parser.go | 52 ++++++++++++++++++++------- 3 files changed, 152 insertions(+), 26 deletions(-) diff --git a/README.MD b/README.MD index f1f01f7..62eae26 100644 --- a/README.MD +++ b/README.MD @@ -1,4 +1,4 @@ -# simpleRequest +_# simpleRequest ## 1. 说明 [simpleRequest](www.github.com/dorlolo/simpleRequest) 是一款面向对象开发的http请求库。他是基于Go原生http库。开发这个模块的主要目的是为了更快的对接http协议的IOT设备。 它具备以下特点: @@ -179,9 +179,95 @@ modeldata:=demo{ r.Body().SetModel(&modeldata) ``` -### 2.7 其它请求参数 +### 2.7 文件上传与转发 +### 2.7.1 文件上传 +```go +var req = sRequest.NewRequest() +req.Headers().ConentType_formData() +req.Body(). + SetFromDataFile("file", "C:\\Users\\lenovo\\Pictures\\Saved Pictures\\demo.jpg"). + Set("fromFormat", "jpg"). + Set("toFormat", "png") +req.TimeOut(15 * time.Second) +resp, err := req.POST("http://xxx/xxx") +if err != nil { + fmt.Println(err.Error()) + return +} +fmt.Println(string(resp)) +``` +### 2.7.2 文件转发 +下面示例中使用gin作为服务端,配合simpleRequest进行文件转发 +1. 通过multipart.FileHeader对象进行转发 +```go +func FileForwardUseMultipartFile(c *gin.Context){ + file,err:=c.FormFile("file") + + var req = sRequest.NewRequest() + req.Headers().ConentType_formData() + req.Body(). + SetFromDataMultipartFile("file", file). + Set("fromFormat", "jpg"). + Set("toFormat", "png") + req.TimeOut(15 * time.Second) + resp, err := req.POST("http://xxx/xxx") + if err != nil { + fmt.Println(err.Error()) + return + } + // parse response and so on + // ... + // ... +``` -#### 2.7.1 设置超时时间 +2. 在一些小众场景下,可能已经在外部构建好了body,此时也可将body转为bytes传入simpleRequest进行请求 +```go +func FileForwardUseBytesBody(c *gin.Context){ + file,err:=c.FormFile("file") + + // body data prepare + vars ( + body = &bytes.Buffer{} + writer = multipart.NewWriter(body) + ) + // add file object + filePart, _ := i.writer.CreateFormFile("file", file.Filename) + src, err := file.Open() + if err != nil { + fmt.Println( err.Error()) + return + } + defer src.Close() + _, err = io.Copy(filePart, src) + if err != nil { + fmt.Println(err.Error()) + return + } + // add other form data + writer.WriteField("fromFormat", "jpg") + writer.WriteField("toFormat","png") + + // post request + _ = writer.close() + var r = simpleRequest.NewRequest() + req.Headers().SetConentType(writer.FormDataContentType()) + req.Body().SetBytes(body.Bytes()) + req.TimeOut(15 * time.Second) + resp, err := req.POST("http://xxx/xxx") + if err != nil { + fmt.Println(err.Error()) + return + } + // parse response and so on + // ... + // ... +} + +``` + +### 2.8 其它请求参数 + +#### 2.8.1 设置超时时间 ```go r.TimeOut(time.Second * 30) ``` @@ -191,8 +277,8 @@ r.TimeOut(time.Second * 30) r.SkipCertVerify() ``` -### 2.8 发送请求 -#### 2.8.1 post请求 +### 2.9 发送请求 +#### 2.9.1 post请求 ```go res, err :=r.POST("https://127.0.0.1:80/excample") if err != nil { @@ -213,17 +299,17 @@ if err != nil { - TRACE -### 2.9 获取上下文 +### 2.10 获取上下文 请注意,需要完成请求后才能获得上下文数据! -#### 2.9.1 获取请求的上下文对象 +#### 2.10.1 获取请求的上下文对象 ```go requestContext:=r.Request ``` -#### 2.9.2 获取返回的上下文对象 +#### 2.10.2 获取返回的上下文对象 ```go responseContext:=r.Response ``` ## 3. 使用示例 -[simpleRequest_test.go](excample/simpleRequest_test.go) \ No newline at end of file +[simpleRequest_test.go](excample/simpleRequest_test.go)_ \ No newline at end of file diff --git a/body.go b/body.go index e63d1c4..64e873b 100644 --- a/body.go +++ b/body.go @@ -7,6 +7,8 @@ package simpleRequest +import "mime/multipart" + // EntryMark 请求体条目标记,用于标记输入的body内容格式 type EntryMark string @@ -15,10 +17,12 @@ func (b EntryMark) string() string { } const ( - StringEntryType EntryMark = "__STRING_ENTRY__" - BytesEntryType EntryMark = "__BYTES_ENTRY__" - ModelEntryType EntryMark = "__MODEL_ENTRY__" - MapEntryType EntryMark = "__MAP_ENTRY__" + StringEntryType EntryMark = "__STRING_ENTRY__" + BytesEntryType EntryMark = "__BYTES_ENTRY__" + ModelEntryType EntryMark = "__MODEL_ENTRY__" + MapEntryType EntryMark = "__MAP_ENTRY__" + MultipartEntryType EntryMark = "__MULTIPART_ENTRY__" + FormFilePathKey EntryMark = "__FORM_FILE_PATH_KEY__" ) type BodyConf struct { @@ -53,3 +57,13 @@ func (s *BodyConf) SetModel(model any) *BodyConf { s.simpleReq.BodyEntries[ModelEntryType.string()] = model return s } +func (s *BodyConf) SetFromDataFile(key, filePath string) *BodyConf { + s.simpleReq.BodyEntryMark = MultipartEntryType + s.simpleReq.BodyEntries[FormFilePathKey.string()+key] = filePath + return s +} +func (s *BodyConf) SetFromDataMultipartFile(key string, multFile *multipart.FileHeader) *BodyConf { + s.simpleReq.BodyEntryMark = MultipartEntryType + s.simpleReq.BodyEntries[key] = multFile + return s +} diff --git a/parser.go b/parser.go index 559f332..6026160 100644 --- a/parser.go +++ b/parser.go @@ -1,4 +1,4 @@ -// Package simpleRequest ----------------------------- +// Package sRequest ----------------------------- // file : parser.go // author : JJXu // contact : wavingBear@163.com @@ -11,6 +11,8 @@ import ( "encoding/json" "io" "mime/multipart" + "os" + "path/filepath" "strings" ) @@ -76,31 +78,55 @@ func (f *FormDataParser) Unmarshal(bodyType EntryMark, BodyEntry map[string]any) } body, f.ContentType = multipartCommonParse(mapper) case StringEntryType: - f.ContentType = formDataType return strings.NewReader(BodyEntry[StringEntryType.string()].(string)) case BytesEntryType: - f.ContentType = formDataType return bytes.NewReader(BodyEntry[BytesEntryType.string()].([]byte)) default: body, f.ContentType = multipartCommonParse(BodyEntry) } - f.ContentType = formDataType - return nil + return } func multipartCommonParse(BodyEntry map[string]any) (reader io.Reader, contentType string) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) for k, sv := range BodyEntry { - switch sv.(type) { - case string: - strSv, _ := sv.(string) - _ = writer.WriteField(k, strSv) - case []string: - sss, _ := sv.([]string) - for _, v := range sss { - _ = writer.WriteField(k, v) + if strings.Contains(k, FormFilePathKey.string()) { + key := k[len(FormFilePathKey):] + path := sv.(string) + filename := filepath.Base(path) + filePart, _ := writer.CreateFormFile(key, filename) + content, err := os.ReadFile(path) + if err != nil { + panic(err) + } + _, _ = filePart.Write(content) + } else { + switch sv.(type) { + case string: + strSv, _ := sv.(string) + _ = writer.WriteField(k, strSv) + case []string: + sss, _ := sv.([]string) + for _, v := range sss { + _ = writer.WriteField(k, v) + } + case *multipart.FileHeader: + file, _ := sv.(*multipart.FileHeader) + filePart, _ := writer.CreateFormFile(k, file.Filename) + src, err := file.Open() + if err != nil { + panic(err) + return + } + defer src.Close() + _, err = io.Copy(filePart, src) + if err != nil { + panic(err) + return + } } } + } err := writer.Close() if err != nil {