2016-08-16 116 views
1

有人可以解釋發生了什麼嗎?如果請求通過值傳遞,http請求值爲空

package main 

import (
    "fmt" 
    "net/http" 
    "strings" 
) 

func Verify(req http.Request) string { 
    return req.FormValue("g-recaptcha-response") 
} 

func main() { 
    req, _ := http.NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not", 
     strings.NewReader("z=post&both=y&prio=2&empty=")) 
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") 
    Verify(*req) 
    fmt.Println(req.FormValue("z")) 
} 

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

這將產生一個空的輸出。 現在如果我在之前訪問值「z」作爲值傳遞請求,它的工作原理!

package main 

import (
    "fmt" 
    "net/http" 
    "strings" 
) 

func Verify(req http.Request) string { 
    return req.FormValue("g-recaptcha-response") 
} 

func main() { 
    req, _ := http.NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not", 
     strings.NewReader("z=post&both=y&prio=2&empty=")) 
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") 
    Verify(*req) 
    fmt.Println(req.FormValue("z")) 
} 

https://play.golang.org/p/5ALnt-pHTl

我試圖與去從1.5到1.7的幾個版本,具有相同的奇結果。 如果請求通過引用傳遞,則它按預期工作。

+1

1. Go中沒有「pass by reference」。 2.永遠不要複製一個http.Request。 3.只處理* http.Request。 – Volker

+0

我同意,但我使用一個lib做這個(https://github.com/haisum/recaptcha/blob/master/recaptcha.go#L46)。這並不能解釋我看到的是什麼: – Gravis

回答

4

這是因爲請求的主體是io.Reader,並且您只能從io.Reader中讀取一次,當您嘗試第二次讀取內容時,沒有更多數據要讀取。

方法FormValue調用ParseForm,它讀取來自閱讀器的所有數據。

+0

換句話說,在對請求做任何事情之前,你可以通過調用'req.ParseForm()'來以一種普遍的方式解決這個問題 – Kaedys

+0

這就是我正在尋找的東西。正在讀取的「副本」不能再用於原始請求,因此爲空字符串。謝謝! – Gravis