转发文件上传

huangapple go评论92阅读模式
英文:

Forwarding a file upload

问题

我正在使用Go语言编写一个API端点,该端点将接受上传的文件并立即转发到另一个API。我不想将文件写入任何地方的磁盘,但我也不确定将文件临时存储在内存中的方式是否正确。我找到的所有示例都涉及将文件保存到磁盘上。我在下面发布了我的代码。我从第二个API收到的响应是我未能上传文件,但我可以看到它接收到了"userID"字段。请问有人能指出我做错了什么,并可能建议这是否是最佳方法?

路由处理程序

func (r *Routes) forwardFile(w http.ResponseWriter, req *http.Request){ 
    parameters := mux.Vars(req)
    userID := parameters["userID"]

    const maxFileSize = 1 * 1024 * 1024 // 1MB

    // 将上传的文件读入内存
    req.ParseMultipartForm(maxFileSize)

    file, fileHeader, err := req.FormFile("fileUpload")
    if err != nil {
        encodeResponse(w, req, response{obj: nil, err: err})
        return
    }
    defer file.Close()

    success, err := service.DoForwardFile(userID, file, fileHeader)
    encodeResponse(w, req, response{obj: success, err: err})
}

服务处理程序

func (b *base) DoForwardFile(userID int, file multipart.File, fileHeader *multipart.FileHeader) (FileForwardedResponse, error) {
    // 开始构建转发文件的请求
    var resp *http.Response
    defer func() {
        if resp != nil {
            resp.Body.Close()
        }
        reportStat.Complete(0)
    }()

    // 构建表单体
    body := &bytes.Buffer{}
    bodyWriter := multipart.NewWriter(body)

    // 添加表单字段
    bodyWriter.WriteField("userID", strconv.Itoa(userID))

    // 将文件添加到表单体中
    fileWriter, err := bodyWriter.CreateFormFile("fileUpload", fileHeader.Filename)
    if err != nil {
        return FileForwardedResponse{}, err
    }
    // 将文件复制到fileWriter中
    _, err = io.Copy(fileWriter, file)
    if err != nil {
        return FileForwardedResponse{}, err
    }
    
    // 关闭表单体写入器
    bodyWriter.Close()

    // 构建请求URL
    apiURL := fmt.Sprintf("%s/v2/users/%d/files", config.APIURL, userID)
    
    // 发送请求
    client := &http.Client{Timeout: time.Second * 10}
    req, err := http.NewRequest("POST", apiURL, body)
    resp, err = client.Do(req)
    
    // ...
}

以上是你提供的代码的翻译。如果你有任何问题,请随时提问。

英文:

I'm working on an api endpoint in go that will accept an upload and then immediately forward to another API. I don't want to write the file to disk anywhere, but I'm not sure storing the file temporarily in memory the way I have is correct either. All the examples that I can find deal with saving the file to disk. I've posted what I'm doing below. The response I get back from the second API is that I failed to post a file, but I can see that it is receiving the "userID" field. Can someone please point out what I'm doing wrong as well as possibly advise if this is the best way to go about this?

Route Handler

func (r *Routes) forwardFile(w http.ResponseWriter, req *http.Request){ 
    parameters := mux.Vars(req)
    userID := parameters["userID"]

    const maxFileSize = 1 * 1024 * 1024 // 1MB

    // pull in the uploaded file into memory
    req.ParseMultipartForm(maxFileSize)


    file, fileHeader, err := req.FormFile("fileUpload")
	if err != nil {
		encodeResponse(w, req, response{obj: nil, err: err})
		return
	}
	defer file.Close()

	success, err := service.DoForwardFile(userID, file, fileHeader)
	encodeResponse(w, req, response{obj: success, err: err})
}

Service Handler

func (b *base) DoForwardFile(userID int, file multipart.File, fileHeader *multipart.FileHeader) (FileForwardedResponse, error) {
    // start building our request to forward the file
  	var resp *http.Response
  	defer func() {
  		if resp != nil {
  			resp.Body.Close()
  		}
  		reportStat.Complete(0)
  	}()
  
  	// build a form body
  	body := &bytes.Buffer{}
  	bodyWriter := multipart.NewWriter(body)
  
  	// add form fields
  	bodyWriter.WriteField("userID", userID)
  
  	// add a form file to the body
  	fileWriter, err := bodyWriter.CreateFormFile("fileUpload", fileHeader.Filename)
  	if err != nil {
  		return FileForwardedResponse{}, err
  	}
  	// copy the file into the fileWriter
  	_, err = io.Copy(fileWriter, file)
  	if err != nil {
  		return FileForwardedResponse{}, err
  	}
  	
  	// Close the body writer
  	bodyWriter.Close()
  
  	// build request url
  	apiURL := fmt.Sprintf("%s/v2/users/%d/files", config.APIURL, userID)
  	
  	// send request
  	client := &http.Client{Timeout: time.Second * 10}
  	req, err := http.NewRequest("POST", apiURL, body)
  	resp, err = client.Do(req)
  	
  	...	

  
  }

答案1

得分: 1

你没有为请求设置Content-Type。即使标头自动设置为multipart/form-data,也缺少数据边界。

req, err := http.NewRequest("POST", uri, body)
if err != nil {
    return FileForwardedResponse{}, err
}
req.Header.Set("Content-Type", bodyWriter.FormDataContentType())
...

你需要在请求中设置Content-TypebodyWriter.FormDataContentType()

英文:

You're not setting the Content-Type for the request. Even if the header gets set automatically to multipart/form-data, it's missing the data boundary.

req, err := http.NewRequest("POST", uri, body)
if err != nil {
    return FileForwardedResponse{}, err
}
req.Header.Set("Content-Type", bodyWriter.FormDataContentType())
...

huangapple
  • 本文由 发表于 2016年9月27日 06:35:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/39713441.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定