2016-08-02 14 views
0

http.Post()的第三個參數允許io.Reader,這意味着返回值os.Open()應該工作。但是下面的代碼會得到意想不到的結果,換句話說,它不會正確設置Content-Length。也許File類型沒有實現。有沒有合適的方法可以用*File來設置Content-Length如何使用os.Open()的返回值作爲http.Post()的第三個參數並設置Content-Length?

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 

https://play.golang.org/p/hJLN2H9Y9p

+0

爲什麼你需要設置Content-Length? – JimB

+0

使用Flask(python)構建的Web應用程序具有'request.stream',並且在發送Content-Length時不起作用。 – Nobu

回答

0

如果你看一下源NewRequest你可以看到,CONTENTLENGTH是爲特定的輸入類型特殊處理,文件閱讀器是不是一個他們。如果這很重要,你必須手動設置Content-Length頭[[分塊也應該可以正常工作,除非你發送到舊的服務器impl]。

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) 
... 
相關問題