英文:
array from form-data in golang return as a string instead of array
问题
我正在翻译以下内容:
我正在从Postman中的表单数据中传递一个数组,在json.Marshal
之前,我得到的是[0558485290,0209739442]
,在使用(bytes.NewBuffer(jsonpayload))
打印时,我得到的是["0558485290,0209739442"]
在JSON Marshal之前
[05583485362290,02097343639442]
在json.Marshal之后
"Recipient":["0558485290,0209739442"]
以下是我的代码
type QuickBulkVoiceCall struct {
Campaign string `form:"campaign"`
Recipient []string `form:"recipient"`
FileHeader *multipart.FileHeader `form:"file_header"`
File string `form:"file"`
VoiceID string `form:"voice_id"`
Is_Schedule bool `form:"is_schedule"`
Schedule_Date string `form:"schedule_date"`
}
func (mnfyCmpgn *MnotifyCampaignService) CreateBulkVoiceCall(blkVcall *models.QuickBulkVoiceCall) (*mnotify.SMSData, error) {
api_key, base_url, err := mnotify.LoadAPIKeys()
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
fmt.Println("Before JSON Marshal", blkVcall.Recipient)
jsonPayload, err := json.Marshal(blkVcall)
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
fmt.Println("JSON Payload: ", bytes.NewBuffer(jsonPayload))
url := (*base_url + "voice/quick/" + "?key=" + *api_key)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
// req.Header.Set("Content-Type", "application/json")
// 发送HTTP请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error: %v", err)
}
responseBody := string(body)
data, err := mnotify.BulkCampaignFilterFilter(responseBody)
if err != nil {
return nil, fmt.Errorf("error: %v", err)
}
return &data, nil
}
func (mnfyCmpgn *MnotifyCampaignController) QuickBulkVoiceCallController(ctx *gin.Context) {
var blkVcCall *models.QuickBulkVoiceCall
err := ctx.ShouldBind(&blkVcCall)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
file, err := ctx.FormFile("file_header")
if err != nil {
// 处理文件未找到的错误
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 将文件保存到Uploads目录
filePath := filepath.Join("./uploads", blkVcCall.FileHeader.Filename)
if err := ctx.SaveUploadedFile(file, filePath); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
}
//
fmt.Println("Recipient", blkVcCall.Recipient)
// 将文件路径分配给结构体文件
blkVcCall.File = filePath
resp, err := mnfyCmpgn.Mnfycntrl.CreateBulkVoiceCall(blkVcCall)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"response": resp,
})
}
英文:
I am passing an array from form data in postman, before the json.Marsal
I get [0558485290,0209739442]
after the json.Marshal
when I print using (bytes.NewBuffer(jsonpayload))
I get ["0558485290,0209739442"]
Before JSON Marshal
[05583485362290,02097343639442]
After json.Marshal
"Recipient":["0558485290,0209739442"]
Below Here is my code
type QuickBulkVoiceCall struct {
Campaign string `form:"campaign"`
Recipient []string `form:"recipient"`
FileHeader *multipart.FileHeader `form:"file_header"`
File string `form:"file"`
VoiceID string `form:"voice_id"`
Is_Schedule bool `form:"is_schedule"`
Schedule_Date string `form:"schedule_date"`
}
func (mnfyCmpgn *MnotifyCampaignService) CreateBulkVoiceCall(blkVcall *models.QuickBulkVoiceCall) (*mnotify.SMSData, error) {
api_key, base_url, err := mnotify.LoadAPIKeys()
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
fmt.Println("Before JSON Marshal", blkVcall.Recipient)
jsonPayload, err := json.Marshal(blkVcall)
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
fmt.Println("JSON Payload: ", bytes.NewBuffer(jsonPayload))
url := (*base_url + "voice/quick/" + "?key=" + *api_key)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
// req.Header.Set("Content-Type", "application/json")
// Make the HTTP Request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error: %v", err.Error())
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error: %v", err)
}
responseBody := string(body)
data, err := mnotify.BulkCampaignFilterFilter(responseBody)
if err != nil {
return nil, fmt.Errorf("error: %v", err)
}
return &data, nil
}
func (mnfyCmpgn *MnotifyCampaignController) QuickBulkVoiceCallController(ctx *gin.Context) {
var blkVcCall *models.QuickBulkVoiceCall
err := ctx.ShouldBind(&blkVcCall)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
file, err := ctx.FormFile("file_header")
if err != nil {
// Handle the error if the file is not found
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Save file to the Uploads directory
filePath := filepath.Join("./uploads", blkVcCall.FileHeader.Filename)
if err := ctx.SaveUploadedFile(file, filePath); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
}
//
fmt.Println("Recipient", blkVcCall.Recipient)
// Lets assign the file path to the struct file
blkVcCall.File = filePath
resp, err := mnfyCmpgn.Mnfycntrl.CreateBulkVoiceCall(blkVcCall)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"response": resp,
})
}
答案1
得分: 1
关于打印输出
在使用json.Marshal
之前,我得到的是[0558485290,0209739442]
,在使用(bytes.NewBuffer(jsonpayload))
打印时,我得到的是["0558485290,0209739442"]
。
请注意,值是
[]string{"0558485290,0209739442"}
而不是
[]string{"0558485290", "0209739442"}
。
看看这个简单的示例:
package main
import "fmt"
func main() {
recipients := []string{"0558485290,0209739442"}
fmt.Println(recipients) // [0558485290,0209739442]
recipients = []string{"0558485290", "0209739442"}
fmt.Println(recipients) // [0558485290 0209739442]
}
在multipart/form-data
请求中发送数组
要在multipart/form-data
请求中向服务器发送数组,可以这样做:
curl 'https://httpbin.org/anything' \
--form 'recipient="0558485290"' \
--form 'recipient="0209739442"' \
--form 'file_header=@"test.data"'
在Postman中对应的请求是:
在multipart/form-data
请求中以JSON值形式发送数组
gin
不太支持在multipart/form-data
请求中使用JSON值。目前,gin
只在目标字段为结构体或映射时尝试解组multipart/form-data
字段中的JSON值(参见此答案:https://stackoverflow.com/a/75989469/1369400)。在OP的情况下,目标字段是一个切片,所以不起作用。顺便说一下,05583485362290,02097343639442
不是一个有效的JSON数组(甚至不是一个有效的JSON值)。有效的JSON数组应该是:["05583485362290","02097343639442"]
。
如果你想将其作为JSON值传递,你必须自己解组该值。请参考下面的示例:
package main
import (
"encoding/json"
"fmt"
"mime/multipart"
"net/http"
"github.com/gin-gonic/gin"
)
type QuickBulkVoiceCall struct {
Recipient []string
FileHeader *multipart.FileHeader `form:"file_header"`
}
func main() {
r := gin.Default()
r.POST("/create", func(ctx *gin.Context) {
type temp struct {
QuickBulkVoiceCall
Recipient string `form:"recipient"`
}
var data temp
err := ctx.ShouldBind(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
blkVcCall := data.QuickBulkVoiceCall
err = json.Unmarshal([]byte(data.Recipient), &blkVcCall.Recipient)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
fmt.Printf("%+v\n", blkVcCall)
})
r.Run()
}
以下是在multipart/form-data
字段中发送JSON值的请求示例:
curl 'http://localhost:8080/create' \
--form 'recipient="[\\"0558485290\\",\\"0209739442\\"]"' \
--form 'file_header=@"test.data"'
以下是相应的Postman请求:
英文:
About the Print Output
> before the json.Marsal
I get [0558485290,0209739442]
after the json.Marshal
when I print using (bytes.NewBuffer(jsonpayload))
I get ["0558485290,0209739442"]
Please note that the value is
[]string{"0558485290,0209739442"}
instead of
[]string{"0558485290", "0209739442"}
.
See this simple demo:
package main
import "fmt"
func main() {
recipients := []string{"0558485290,0209739442"}
fmt.Println(recipients) // [0558485290,0209739442]
recipients = []string{"0558485290", "0209739442"}
fmt.Println(recipients) // [0558485290 0209739442]
}
Send Array in multipart/form-data
Request
To send an array to the server in a multipart/form-data
request, you can do it like this:
curl 'https://httpbin.org/anything' \
--form 'recipient="0558485290"' \
--form 'recipient="0209739442"' \
--form 'file_header=@"test.data"'
The corresponding request in postman is:
Send Array as JSON value in multipart/form-data
Request
gin
does not support JSON in multipart/form-data
request very well. As of now, gin
tries to unmarshal a JSON value in a multipart/form-data
field only when the target field is a struct or a map (see this answer: https://stackoverflow.com/a/75989469/1369400). In the OP's case, the target field is a slice, so it does not work. BTW, 05583485362290,02097343639442
is not a valid JSON array (it's even not a valid JSON value). The valid JSON array should be: ["05583485362290","02097343639442"]
.
If you want to pass it as a JSON value, you have to unmarshal the value yourself. See the demo below:
package main
import (
"encoding/json"
"fmt"
"mime/multipart"
"net/http"
"github.com/gin-gonic/gin"
)
type QuickBulkVoiceCall struct {
Recipient []string
FileHeader *multipart.FileHeader `form:"file_header"`
}
func main() {
r := gin.Default()
r.POST("/create", func(ctx *gin.Context) {
type temp struct {
QuickBulkVoiceCall
Recipient string `form:"recipient"`
}
var data temp
err := ctx.ShouldBind(&data)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
blkVcCall := data.QuickBulkVoiceCall
err = json.Unmarshal([]byte(data.Recipient), &blkVcCall.Recipient)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
fmt.Printf("%+v\n", blkVcCall)
})
r.Run()
}
Here is the request to send the JSON value in a multipart/form-data
field:
curl 'http://localhost:8080/create' \
--form 'recipient="[\"0558485290\",\"0209739442\"]"' \
--form 'file_header=@"test.data"'
And here is the corresponding postman request:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论