英文:
http.Request RequestURI field when making request in go
问题
你在服务器上将请求转储为[]byte
,然后使用ReadRequest
方法创建了一个请求,并使用Client.Do
方法发送请求。你遇到了一个错误:
http: Request.RequestURI无法在客户端请求中设置。
你能解释一下为什么会出现这个错误吗?
英文:
I dumped request from server to []byte
and used ReadRequest
to make a request with Client.Do
method. I got an error:
> http: Request.RequestURI can't be set in client requests.
Can you explain me why exactly I got this error?
答案1
得分: 17
错误很明显:在进行客户端请求时,不允许设置RequestURI。
在http.Request.RequestURI
的文档中,它说(我强调):
>RequestURI是客户端发送给服务器的Request-Line(RFC 2616,第5.1节)的未修改的Request-URI。通常应该使用URL字段。在HTTP客户端请求中设置此字段是错误的。
设置RequestURI的原因是在解析请求流时ReadRequest会这样做。
因此,如果要发送请求,您需要设置URL并清除RequestURI。在尝试后,我注意到从ReadRequest返回的请求中的URL对象不会设置所有信息,例如scheme和host。因此,您需要自己设置它,或者只需使用net/url
包中的Parse解析一个新的URL:
以下是一些可工作的代码示例:
package main
import (
"fmt"
"strings"
"bufio"
"net/http"
"net/url"
)
var rawRequest = `GET /pkg/net/http/ HTTP/1.1
Host: golang.org
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; de-de) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
Cache-Control: no-cache
Accept-Language: de,en;q=0.7,en-us;q=0.3
`
func main() {
b := bufio.NewReader(strings.NewReader(rawRequest))
req, err := http.ReadRequest(b)
if err != nil {
panic(err)
}
// 我们不能设置这个字段。而且它只包含"/pkg/net/http/"。
req.RequestURI = ""
// 由于req.URL不会设置所有信息,例如协议方案和主机,我们创建一个新的URL。
u, err := url.Parse("http://golang.org/pkg/net/http/")
if err != nil {
panic(err)
}
req.URL = u
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", resp)
}
注意:play.golang.org会发生错误,因为我们没有执行HTTP请求的权限。
英文:
The error is clear: You are not allowed to have RequestURI set when doing a client request.
In the documentation for http.Request.RequestURI
, it says (my emphasis):
>RequestURI is the unmodified Request-URI of the
>Request-Line (RFC 2616, Section 5.1) as sent by the client
>to a server. Usually the URL field should be used instead.
>It is an error to set this field in an HTTP client request.
The reason why it is set is because that is what ReadRequest does when parsing the request stream.
So, you need to set the URL and clear the RequestURI if you want to send it. After making an attempt, I noticed that the URL object in the request returned from ReadRequest will not have all the information set, such as scheme and host. Due to this, you will need to set it yourself, or just parse a new URL using Parse in the net/url
package:
Here is some working code for you:
package main
import (
"fmt"
"strings"
"bufio"
"net/http"
"net/url"
)
var rawRequest = `GET /pkg/net/http/ HTTP/1.1
Host: golang.org
Connection: close
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; de-de) AppleWebKit/523.10.3 (KHTML, like Gecko) Version/3.0.4 Safari/523.10
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7
Cache-Control: no-cache
Accept-Language: de,en;q=0.7,en-us;q=0.3
`
func main() {
b := bufio.NewReader(strings.NewReader(rawRequest))
req, err := http.ReadRequest(b)
if err != nil {
panic(err)
}
// We can't have this set. And it only contains "/pkg/net/http/" anyway
req.RequestURI = ""
// Since the req.URL will not have all the information set,
// such as protocol scheme and host, we create a new URL
u, err := url.Parse("http://golang.org/pkg/net/http/")
if err != nil {
panic(err)
}
req.URL = u
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", resp)
}
Ps. play.golang.org will panic, since we don't have the permission to do http requests.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论