【问题标题】:Empty response after file upload文件上传后的空响应
【发布时间】:2018-09-21 13:34:19
【问题描述】:

我在 Go 中编写了一个小的 REST api,我正在使用相同的函数返回一个带有状态代码和消息的 http.Response:

type apiResponse struct {
    Status  int    `json:"status"`
    Message string `json:"message"`
}

我将其编组为 json 字符串并使用 w.Write() 将其放入响应中。

API 具有三个端点,其中一个允许用户上传文件。两个工作得很好,我得到了我期望的回应。 上传端点返回一个带有Content-Length 的有效响应,它与我期望的消息相匹配,但是当我阅读它时(使用ioutil.ReadAll),它是空的!

我做错了什么?

这是读取正文的函数:

func readResponseContent(resp *http.Response) string {
    defer resp.Body.Close()
    fmt.Println(resp)
    fmt.Println(resp.ContentLength)
    bodyBytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Error in response: %s", err.Error())
        os.Exit(1)
    }
    bodyString := string(bodyBytes)
    return bodyString
}

这是处理程序:

func handleSubmission(w http.ResponseWriter, r *http.Request) {

var Buf bytes.Buffer
file, header, err := r.FormFile(audioUploadKey)

if err != nil {
    log.Printf("Error uploading file: %s\n", err.Error())
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
defer file.Close()

jobID, _ := uuid.NewUUID()
_ = os.MkdirAll(path.Join(jobsPath, jobID.String()), 0750)

log.Printf("Received file %s\n", header.Filename)

io.Copy(&Buf, file)
fileOut, _ := os.Create(path.Join(jobsPath, jobID.String(), 

Buf.WriteTo(fileOut)
Buf.Reset()

// submit
// DO STUFF with jobID

apiResp := apiResponse{Status:http.StatusCreated, Message:jobID.String()}
jsonResp, _ := json.Marshal(apiResp)
writeJSONResponse(w, jsonResp)
return}

【问题讨论】:

  • 显示writeJSONResponse的代码。
  • 在将响应正文传递给 readResponseContent 之前,您确定没有其他人正在读取响应正文?
  • 您使用下划线返回错误只是为了让您的代码更小吗?鉴于您的代码实际上 确实 在那里检查了两次错误,我怀疑不是。如果这些下划线出现在您的实际代码中,请停止忽略错误。我看到 99.9% 的 json 编组/解组失败的问题是因为人们忽略了他们的错误并错过了一个完美解释的错误返回值。
  • 我只是用它们来缩短这里的功能。我正在检查一切是否符合预期(正确的文件、正确的副本、正确的 ID,...)。
  • writeJSONResponse 只需要一个[]byte,将内容类型设置为 json 并写入字节

标签: rest http go response


【解决方案1】:

问题看起来你忘记了你收到的表单的内容类型,当你发送 json 时,内容类型是 aplication/json,当你上传文件时,你应该使用 multipart/form-data,如果是这种情况,您可以这样阅读:

    import(
       "ioutil"
       "net/http"
    )
//check all posible errors, I´m assuming you just have one file per key
    func handler(w http.ResponseWriter, r *http.Request) {
        r.ParseMultipartForm(1000000) //1 MB in memory, the rest in disk
        datas := r.MultipartForm
        for k, headers := range datas.File {
            auxiliar, _ := headers[0].Open() //first check len(headers) if it's correct
            fileName:=headers[0].Filename
            file, _ := ioutil.ReadAll(auxiliar)
            // do what you need to do with the file
    }
}
at the frontEnd you should have some javascript like this:

function handleFile(url,file){
  let data=new FormData();
  data.append("key",file); //this is the key when ranging over map at backEnd
  fetch(url,{method:"PUT",body:data})
}

【讨论】:

  • 这或多或少是what http.Request.FormFile does。这与意外的空响应无关。
  • 我说是因为他正在像这样 bodyBytes 读取文件的正文,err := ioutil.ReadAll(resp.Body)
【解决方案2】:

发现问题...在生成响应之前,单独函数中的一段代码正在消耗 Body...

学习一门新语言的挫折和错误:/

【讨论】:

    猜你喜欢
    • 2017-02-25
    • 2021-09-13
    • 2021-06-01
    • 2017-03-15
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多