[zeromicro/go-zero]POST请求的表单数据

2024-01-10 965 views
2

你好,我用 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 后续会不会有更好的方法。

回答

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"`
    }
)

Snipaste_2021-02-02_01-12-26

debug的过程如下,不知道怎么把上传的file文件对应到 UploadReq : Snipaste_2021-02-02_01-37-21

如果 .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
}