http.Post()
的第三个参数允许io.Reader
,这意味着os.Open()
的返回值应该有效。但是下面的代码会得到意想不到的结果,换句话说,它不会正确设置Content-Length
。也许File
类型没有实现某些东西。有没有正确的方法可以Content-Length
设置*File
?
package main
import (
"bytes"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"os"
)
var sample = []byte(`hello`)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.Header)
if int(r.ContentLength) != len(sample) {
log.Fatal("Unexpected Content-Length:", r.ContentLength)
}
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{}`))
}))
defer ts.Close()
file, err := ioutil.TempFile(os.TempDir(), "")
if err != nil {
log.Fatal(err)
}
defer os.Remove(file.Name())
file.Write(sample)
// This works
buf, err := ioutil.ReadFile(file.Name())
if err != nil {
log.Fatal(err)
}
_, err = http.Post(ts.URL, "application/octet-stream", bytes.NewBuffer(buf))
if err != nil {
log.Fatal(err)
}
// This looks fine in my opinion, though it doesn't set Content-Length
f, err := os.Open(file.Name())
if err != nil {
log.Fatal(err)
}
_, err = http.Post(ts.URL, "application/octet-stream", f)
if err != nil {
log.Fatal(err)
}
}
输出:
2009/11/10 23:00:00 map[Content-Type:[application/octet-stream] Accept-Encoding:[gzip] User-Agent:[Go-http-client/1.1] Content-Length:[5]]
2009/11/10 23:00:00 map[Content-Type:[application/octet-stream] Accept-Encoding:[gzip] User-Agent:[Go-http-client/1.1]]
2009/11/10 23:00:00 Unexpected Content-Length:-1
答案 0 :(得分:0)
如果您查看NewRequest的来源,您会发现contentLength是针对特定输入类型专门处理的,而文件阅读器并不是其中之一。您必须手动设置Content-Length标头,如果重要的那样[chunked也应该正常工作,除非您发送到旧服务器impl]。
答案 1 :(得分:0)
如果要添加Content-Length
,则需要对文件进行统计以获取大小。 ContentLength不会自动计算,因为os.File
可能没有有用的大小。
f, err := os.Open(file.Name())
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", ts.URL, f)
if err != nil {
log.Fatal(err)
}
stat, err := f.Stat()
if err != nil {
log.Fatal(err)
}
req.ContentLength = stat.Size()
req.Header.Set("Content-Type", "application/octet-stream")
resp, err = http.Do(req)
...