你好,我用 POST 请求,以 multipart/form-data 的形式上传文件。在处理请求的 handler.go 用 github.com/tal-tech/go-zero/rest/httpx 的 Parse 方法去获取参数。httpx.Parse 只有解析 Request.Form 里面的参数,没有解析 Request.MultipartForm 的参数。不幸的是,multipart/form-data 请求的参数是存放在 Request.MultipartForm 里面,Request.Form 是一个空的对象。 是因为实际使用场景中,不会以 multipart/form-data 方式上传数据,还是什么原因呢? 目前我是从 Request 对象了里面解析,不知道 httpx.Parse 后续会不会有更好的方法。
Q
[zeromicro/go-zero]POST请求的表单数据
2
A
回答
3
httpx.Parse是会解析multipart-form的,你用form tag定义的嘛?
4
非常感谢老师的答复。我测试之后, httpx.Parse 确实是会解析multipart-form的 键值对 。
如果form表单中,存在上传文件的情况下,我不知道应该怎么处理。 我定义如下的api文件(只有一个文件字段),并请求服务
type (
UploadReq {
File string `form:"file"`
}
UploadResp {
Msg string `json:"msg"`
}
)
debug的过程如下,不知道怎么把上传的file文件对应到 UploadReq :
如果 .api 文件是想上传文件的话,对应的类型应该是什么呢? 我从 type语法块 也没有找到合适的。 目前的办法是把文件转成byte字符串,然后作为键值对上传,服务端接收到byte之后,再写入文件。
3
关于文件这块可以自己补充解析函数:
const (
defaultMultipartMemory = 32 << 20 // 32 MB
)
func FromFile(r *http.Request, name string) (*multipart.FileHeader, error) {
if r.MultipartForm == nil {
if err := r.ParseMultipartForm(defaultMultipartMemory); err != nil {
return nil, err
}
}
f, fh, err := r.FormFile(name)
if err != nil {
return nil, err
}
f.Close()
return fh, err
}
其中name为multipart-form里文件对应的字段。
3
所以 .api 文件是想上传文件的话,对应的类型应该是什么呢? 可以说一下吗
1
上传文件不推荐用go-zero处理,可以直接上传oss等。
8
我试了下, 参考 @sliveryou 的代码,可以不走api文件,而是可以直接在handler那里通过 http.Request
对象拿到multipart-from里的文件,handler部分的代码如下:
const (
defaultMultipartMemory = 32 << 20 // 32 MB
)
func addHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(defaultMultipartMemory); err != nil {
httpx.Error(w, err)
return
}
l := logic.NewAddLogic(r.Context(), ctx)
uploadedFiles := r.MultipartForm.File
for key, files := range uploadedFiles {
if strings.HasPrefix(key, "media") {
l.Files = append(l.Files, files...)
}
}
resp, err := l.Add()
if err != nil {
httpx.Error(w, err)
} else {
httpx.OkJson(w, resp)
}
}
}
API文件部分是这样写的:
@doc "add media"
@handler add
post /add () returns (AddResp)
9
大佬,logic的文件能看一下不~
5
logic里涉及到文件处理的具体代码大概是以下这样的:
func (l *AddLogic) Add() (*types.AddResp, error) {
// do something
for _, file := range l.Files {
sendMedia(file, requestURL)
}
resp := &types.AddResp{}
for v := range respChan {
resp.Cid = append(resp.Cid, v)
}
return &types.AddResp{}, nil
}
func sendMedia(media *multipart.FileHeader, apiURL string) {
// do something
file, err := media.Open()
if err != nil {
logx.Errorf("filed to read file from multipart: %s", err)
}
resp, err := http.Post(apiURL, "multipart/form-data", file)
// do something
}