array from form-data in golang return as a string instead of array

huangapple go评论79阅读模式
英文:

array from form-data in golang return as a string instead of array

问题

我正在翻译以下内容:

我正在从Postman中的表单数据中传递一个数组,在json.Marshal之前,我得到的是[0558485290,0209739442],在使用(bytes.NewBuffer(jsonpayload))打印时,我得到的是["0558485290,0209739442"]

array from form-data in golang return as a string instead of array

在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"]

array from form-data in golang return as a string instead of array

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中对应的请求是:

array from form-data in golang return as a string instead of array

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请求:

array from form-data in golang return as a string instead of array

英文:

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:

array from form-data in golang return as a string instead of array

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:

array from form-data in golang return as a string instead of array

huangapple
  • 本文由 发表于 2023年6月20日 00:20:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76508448.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定