2016-08-16 156 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