【问题标题】:Echo web framework binding FormFileEcho web 框架绑定 FormFile
【发布时间】:2020-09-07 00:58:22
【问题描述】:

我正在将 Echo 框架用于接受表单数据的 post 端点。我使用 Struct 作为绑定模型来提取表单数据。我的绑定模型和上传处理程序代码如下所示。

 type FormModel struct {
    ID string                `form:"ID"`
    FirstName string                `form:"FirstName"`
    File      *multipart.FileHeader `form:"myFileName"`
}

func (cs *handler) uploadForm(c echo.Context) error {
s := new(FormModel)
if err := c.Bind(s); err != nil {
    return nil
}

fileHandler, err := c.FormFile("myFileName")

我可以通过绑定获得 ID 和 FirstName 等表单值。但我无法在绑定期间获取文件。我必须使用fileHandler, err := c.FormFile("myFileName") 来获取文件。有没有办法在绑定模型中获取文件信息?

【问题讨论】:

    标签: go go-echo


    【解决方案1】:

    echo默认不支持绑定multipart.Form.File数据,需要重新绑定实现接口。

    为echo Bind封装了一层额外的bind FormFile。如果结构指针类型的属性类型为*multipart.FileHeader或[]*multipart.FileHeader,则该属性将通过反射设置为FormFile的值。

    我大概实现了这个功能。没用过echo也没测试过,但是思路是对的。

    
    var (
        typeMultipartFileHeader      = reflect.TypeOf((*multipart.FileHeader)(nil)).Elem()
        typeMultipartSliceFileHeader = reflect.TypeOf(([]*multipart.FileHeader)(nil)).Elem()
    )
    
    func main() {
        app := echo.New()
        // warp bind suppet bind FormFile
        app.Binder = NewBindFile(app.Binder)
    }
    
    type BindFunc func(interface{}, echo.Context) error
    
    func (fn BindFunc) Bind(i interface{}, ctx echo.Context) error {
        return fn(i, ctx)
    }
    
    func NewBindFile(b echo.Binder) echo.Binder {
        return BindFunc(func(i interface{}, ctx echo.Context) error {
            err := b.Bind(i, ctx)
            if err == nil {
                ctype := crx.Request.Header.Get(echo.HeaderContentType)
                // if bind form
                if strings.HasPrefix(ctype, echo.MIMEApplicationForm) || strings.HasPrefix(ctype, echo.MIMEMultipartForm) {
                    // get form files
                    var form *multipart.Form
                    form, err = ctx.MultipartForm()
                    if err == nil {
                        err = EchoBindFile(i, ctx, form.File)
                    }
                }
            }
            return err
        })
    }
    
    func EchoBindFile(i interface{}, ctx echo.Context, files map[string][]*FileHeader) error {
        iValue := reflect.Indirect(reflect.ValueOf(i))
        // check bind type is struct pointer
        if iValue.Kind() != reflect.Struct {
            return fmt.Errorf("BindFile input not is struct pointer, indirect type is %s", iValue.Type().String())
        }
    
        iType := iValue.Type()
        for i := 0; i < iType.NumField(); i++ {
            fType := iType.Field(i)
            // check canset field
            fValue := iValue.Field(i)
            if !fValue.CanSet() {
                continue
            }
            // revc type must *multipart.FileHeader or []*multipart.FileHeader
            switch fType.Type {
            case typeMultipartFileHeader:
                file := getFiles(files, fType.Name, fType.Tag.Get("form"))
                if file != nil && len(file) > 0 {
                    fValue.Set(reflect.ValueOf(file[0]))
                }
            case typeMultipartSliceFileHeader:
                file := getFiles(files, fType.Name, fType.Tag.Get("form"))
                if file != nil && len(file) > 0 {
                    fValue.Set(reflect.ValueOf(file))
                }
            }
        }
        return nil
    }
    
    func getFiles(files map[string][]*FileHeader, names ...string) []*FileHeader {
        for _, name := range names {
            file, ok := files[name]
            if ok {
                return file
            }
        }
        return nil
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 1970-01-01
      • 2019-06-21
      • 2016-04-16
      • 1970-01-01
      • 2022-10-21
      相关资源
      最近更新 更多