通过将os.Open中的io.Reader传递给http.Post(HTTP)POST本地文件时,Content-Length为零

时间:2016-12-29 11:15:02

标签: go

heya everyone:得到一个简短的问题,我想发帖(http)一个文件。我想,因为os.Open返回一个io.Reader而http.Post需要一个io.Reader我没有在一个单独的步骤中将文件读入内存,只能绕过Reader。 但是,Content-Length将被设置为零 - 这有点意义,但不是我需要的。

file, _ := os.Open("some file")
req, _ := http.NewRequest("POST", "some url", file)
dump, _ := httputil.DumpRequestOut(req, false)
fmt.Println(string(dump))

我的问题:我是否必须将文件读入内存(使用ioutil.ReadFile或其他类似内容)并创建一个新的阅读器或有没有办法将阅读器从文件直接传递到邮政请求没有"阅读"步骤

我想我可以通过file.Stat来设置Content-Length,但我想知道是否有更优雅的方式来做这个?

2 个答案:

答案 0 :(得分:2)

简短的回答是:你绝对正确地将os.File提供给http.Request以及使用os.File.Stat()获取文件大小并在http.Request标头上设置它。我个人认为这是最简单的方法。

file, _ := os.Open("some file")
info, _ := file.Stat()
req, _ := http.NewRequest("POST", "http://bla.com", file)
req.ContentLength = info.Size()
dump, _ := httputil.DumpRequestOut(req, false)
fmt.Println(string(dump))

另请注意,根据http.Request.Write() documentation(我引用):

  

如果存在Body,则Content-Length为< = 0而TransferEncoding尚未   被设置为“identity”,Write将“Transfer-Encoding:chunked”添加到   头。身体在发送后关闭。

因此,在这种情况下,客户本身会做(可以说)最明智的事情为你做。

答案 1 :(得分:0)

是的,它可以传递任何直接返回的os.Open()作为HTTP请求的正文。

但是只有两种方法来处理该文件数据的内容长度。它们是不同的,但它们都围绕着接收方必须提前知道内容长度的想法 - 也就是说,从HTTP响应头部在主体之前接收或者它必须使用允许不知道它的机制,然后发件人必须有办法发出信号表明它已完成发送数据。

  • A" classic"即使使用HTTP / 1.0-一次工作也是在发送之前计算它。这确实意味着将整个内容读入内存或进行stat调用(您可以在打开的文件BTW上执行此操作)。

  • HTTP / 1.1支持它发送的所谓"chunked" transfer encoding数据。 在这种情况下,有效载荷被切成碎片,每个碎片依次使用某些框架发送。特殊帧表示数据流的结束。在这种情况下,可以将Content-Type设置为0,但客户端必须支持分块编码(并非所有都支持)。