如何在Beego中实现application/octet-stream类型的文件上传?
Beego控制器兼容multipart/form-data和application/octet-stream文件上传
我写了一段Beego控制器代码用于文件上传,但它只支持multipart/form-data类型的请求,用它处理application/octet-stream类型的请求时会返回500错误,怎么修改才能支持两种类型?
原代码:
func (this *MainController) Post() { file, header, err := this.GetFile("file") if err != nil { panic(fmt.Sprintf("failed to get uploaded file: %v", err)) } defer file.Close() // 指定保存上传文件的目录 // 把"/pacthOFuploadfile"替换成你想要的目录路径 fileDir := "/pacthOFuploadfile" err = os.MkdirAll(fileDir, os.ModePerm) if err != nil { panic(fmt.Sprintf("failed to create file directory: %v", err)) } filePath := fmt.Sprintf("%s/%s", fileDir, header.Filename) out, err := os.Create(filePath) if err != nil { panic(fmt.Sprintf("failed to create file: %v", err)) } defer out.Close() _, err = io.Copy(out, file) if err != nil { panic(fmt.Sprintf("failed to save file: %v", err)) } this.Ctx.WriteString("File uploaded successfully!") }
解决方案
原代码的GetFile方法是专门处理multipart/form-data请求里的表单文件字段的,而application/octet-stream类型的请求是把整个请求体作为文件内容,没有表单字段,直接调用GetFile必然报错。下面是兼容两种请求类型的修改代码:
import ( "fmt" "io" "net/http" "os" "strings" ) func (this *MainController) Post() { fileDir := "/path/to/upload/directory" // 替换为实际存储目录 err := os.MkdirAll(fileDir, os.ModePerm) if err != nil { this.Ctx.ResponseWriter.WriteHeader(http.StatusInternalServerError) this.Ctx.WriteString(fmt.Sprintf("创建目录失败: %v", err)) return } var ( fileReader io.Reader fileName string ) contentType := this.Ctx.Request.Header.Get("Content-Type") switch { case strings.HasPrefix(contentType, "multipart/form-data"): // 处理表单上传类型 file, header, err := this.GetFile("file") if err != nil { this.Ctx.ResponseWriter.WriteHeader(http.StatusBadRequest) this.Ctx.WriteString(fmt.Sprintf("获取表单文件失败: %v", err)) return } defer file.Close() fileReader = file fileName = header.Filename case strings.HasPrefix(contentType, "application/octet-stream"): // 处理二进制流上传类型 fileReader = this.Ctx.Request.Body defer this.Ctx.Request.Body.Close() // 从请求头尝试获取文件名,无则用默认名 disp := this.Ctx.Request.Header.Get("Content-Disposition") if disp != "" { parts := strings.Split(disp, ";") for _, part := range parts { part = strings.TrimSpace(part) if strings.HasPrefix(part, "filename=") { fileName = strings.Trim(strings.TrimPrefix(part, "filename="), "\"'") break } } } if fileName == "" { fileName = "default_upload.bin" } default: this.Ctx.ResponseWriter.WriteHeader(http.StatusUnsupportedMediaType) this.Ctx.WriteString("不支持的请求类型,仅接受multipart/form-data和application/octet-stream") return } // 保存文件到本地 filePath := fmt.Sprintf("%s/%s", fileDir, fileName) out, err := os.Create(filePath) if err != nil { this.Ctx.ResponseWriter.WriteHeader(http.StatusInternalServerError) this.Ctx.WriteString(fmt.Sprintf("创建文件失败: %v", err)) return } defer out.Close() _, err = io.Copy(out, fileReader) if err != nil { this.Ctx.ResponseWriter.WriteHeader(http.StatusInternalServerError) this.Ctx.WriteString(fmt.Sprintf("保存文件失败: %v", err)) return } this.Ctx.WriteString("文件上传成功!") }
关键修改说明
- 请求类型判断:通过读取
Content-Type头区分两种上传方式,返回对应错误给不支持的类型 - 二进制流处理:直接读取请求体
this.Ctx.Request.Body作为文件内容,无需表单字段 - 文件名获取:尝试从
Content-Disposition头提取文件名,无则使用默认名称 - 错误处理优化:移除
panic,改用标准HTTP状态码返回错误信息,更符合Web服务规范
内容的提问来源于stack exchange,提问作者NoOne
相关产品推荐
相关产品推荐

