I think the story of go's nil is the nth decoction, but I will write an article to commemorate my addiction.
Since the actual code is a little longer and is in the framework, it was difficult to identify the cause, but I will write only the essence.
By the way, I intended to be a wrapper function because I throw HTTPRequest many times in the test code.
func Request(method, url string, body *strings.Reader) error {
request, err := http.NewRequest(method, url, body)
if err != nil {
return err
}
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := new(http.Client)
resp, _ := client.Do(request)
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(byteArray))
return nil
}
I'm assuming you'll use this method this way.
func main() {
values := url.Values{
"hoge": []string{"fuga"},
}
err := Request("POST", "https://google.com", strings.NewReader(values.Encode()))
if err != nil {
log.Fatal(err)
}
}
For the 3rd argument of Request, ~~ Roughly ~~ I specified the return type of strings.NewReader as it is without thinking about anything.
Now, when there is nothing to send parameters in POST
err := Request("POST", "https://google.com", nil)
if err != nil {
log.Fatal(err)
}
I specify, but when I execute this
Crash with run-time error.
strings.(*Reader).Len(...)
/usr/local/Cellar/go/1.15.3/libexec/src/strings/reader.go:26
net/http.NewRequestWithContext(0x1314620, 0xc00001a0b0, 0x12baeec, 0x3, 0x12be7e1, 0x12, 0x13102c0, 0x0, 0x121018d, 0x0, ...)
/usr/local/Cellar/go/1.15.3/libexec/src/net/http/request.go:889 +0x2a4
net/http.NewRequest(...)
/usr/local/Cellar/go/1.15.3/libexec/src/net/http/request.go:813
main.Request(0x12baeec, 0x3, 0x12be7e1, 0x12, 0x0, 0x0, 0x0)
By the way, it's okay if you specify nil directly in the third argument of http.NewRequest.
req, err := http.NewRequest("POST", "https://google.com", nil)
if err != nil {
log.Fatal(err)
}
As you can see by stepping through IntelliJ IDEA,
https://github.com/golang/go/blob/f2eea4c1dc37886939c010daff89c03d5a3825be/src/net/http/request.go#L887
if body != nil {
Go's nil is a typed semantics, so it goes inside the function with the type of * strings.NewReader, even though the body itself is nil in the code below. Since the type of the body content itself is * strings.NewReader and the body declaration is io.Reader The nil judgment is true (unintentionally?), And it means that it is in the if and an error occurs.
reference: https://qiita.com/umisama/items/e215d49138e949d7f805
req, err := http.NewRequest("POST", "https://google.com", nil)
Well, the nil specified here, but from the definition of NewRequest It becomes nil of io.Reader. (io.Reader is also typed in interface)
func Request(method, url string, body *strings.Reader)
Arguments of
func Request(method, url string, body io.Reader)
It should have been, so even though it is a disposable function in the test, It was safe to match the function argument to the type of the function used inside, not the type of the caller.
When nil is specified in the 3rd argument of http.NewRequest, specify it to be the type of io.Reader.
Declare function arguments as close to the type called inside as possible.
It is often said that nil is addicted to it, but I thought that I wouldn't notice it unless I was actually addicted to it.
Recommended Posts