HTTPリクエストの送信
Webページなどでデータをやりとりする際は、HTTPという取り決めに従う必要がある。Goの標準パッケージを利用して、HTTPリクエストを送信する。
Getリクエストの送信
net/httpは、WebサーバやWebクライアントを作るためのパッケージ。
http.Get関数では、指定したURLにGETリクエストを送信できる。ここでは、「http://example.com」にアクセスし、返り値を変数respに格納する。エラーハンドリングは行わず、_でエラーは無視する。
また、Getリクエストの結果であるレスポンスボディは、クローズする必要があるので「defer resp.Body.Close()」を実行しておく。
次に「io.ReadAll(resp.Body)」で読み取った内容を変数bodyに代入する。最後に、「fmt.Println(string(body))」で表示すると、アクセスしたURLのHTMLが表示される。
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("http://example.com")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
※補足
急に出てきたresp.Bodyってなんだと思ったので調べると、
respは、HTTPステータスコード、ヘッダー、および本文を含むHTTPレスポンス全体を表すオブジェクトで、HTTPレスポンスの本文(ボディ)のみを表したのがresp.Bodyということだった。
※補足終わり
net/urlパッケージでURLの解析を行う。
URLが正しい形式か解析するには、net/urlパッケージをインポートしてurl.Parse関数を使う。url.Parse関数は、引数に渡した文字列を解析し、返り値としてURL型の構造体を返す。文字列がURLの形式でなかればエラーを返す。
「http://example.com」を解析してみる。
package main
import (
"fmt"
"net/url"
)
func main() {
base, err := url.Parse("http://example.com")
fmt.Println(base, err)
}
結果は以下のように表示される
URL部分を編集して、エラーが起こるようにしてみる。
package main
import (
"fmt"
"net/url"
)
func main() {
base, err := url.Parse("http://exam ple.com") //スペースを入れる
fmt.Println(base, err)
}
クエリパラメータの追加
HTTPリクエストの際、URLの後ろに追加して渡す値のことを、クエリパラメータという。クエリパラメータによりサーバーに対して特定のリクエストを行う。
「http://example.com/test?a=1&b=2」というURLの場合、「?a=1&b=2」のように?の後ろに追加しているのがクエリパラメータ。
このクエリパラメータは、変数aに1、変数bに2をそれぞれ指定している。
ResolveReferenceメソッドを使用するとクエリパラメータを追加することができる。
まず、url.Parse関数で「http://example.com」のあとにつなげるURL「/test?a=1&b=2」を書き、変数referenceに代入する。
次に、変数baseと変数referenceから、アクセスするURLを生成する。「base.ResolveReference(reference)」として変数baseと変数referenceをつなげたURLを作成し、String()で文字列にして、変数endpointに代入する。
package main
import (
"fmt"
"net/url"
)
func main() {
base, _ := url.Parse("http://example.com")
reference, _ := url.Parse("/test?a=1&b=2")
endpoint := base.ResolveReference(reference).String()
fmt.Println(endpoint)
}
表示結果は以下のようになりクエリパラメータが追加されていることが分かる。
http.NewRequest関数でリクエストを作成する
http.NewRequest関数でリクエストを作成し、Getリクエストを送信する方法を実行する。
まずは、http.NewRequest関数でリクエストを作成する。引数にはHTTPメソッドとURLをそれぞれ一つ目、二つ目に指定する。三つ目の引数は、リクエストボディ(送信するデータ)を指定するが、今回はGETメソッドなのでnilを指定。(リクエストボディはPOSTなどを使用する際に指定する。)
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
base, _ := url.Parse("http://example.com")
reference, _ := url.Parse("/test?a=1&b=2")
endpoint := base.ResolveReference(reference).String()
fmt.Println(endpoint)
req, _ := http.NewRequest("Get", endpoint, nil)
}
上記のコードで変数reqに代入したHTTPリクエストは変数endpointに代入したURL「http://example.com/test?a=1&b=2」を指定している。このクエリパラメータは、「req/URL.Query()」のようにQueryメソッドで取り出すことができる。
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
base, _ := url.Parse("http://example.com")
reference, _ := url.Parse("/test?a=1&b=2")
endpoint := base.ResolveReference(reference).String()
fmt.Println(endpoint)
req, _ := http.NewRequest("Get", endpoint, nil)
q := req.URL.Query()
fmt.Println(q)
}
Addメソッドでクエリパラメータを追加する
http.NewRequest関数でリクエストを作成する場合はAddメソッドでクエリパラメータを追加できる。
次のコードでは。「q.Add("c","3&%")」で変数qにクエリパラメータを追加している。
変数qのクエリパラメータを、変数reqのHTTPリクエストに反映するには、「req.URL.RawQueery」に値を代入する。ただしその際にq.Encode()のようにして、Encodeメソッドを使ってエンコードする必要がある。
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
base, _ := url.Parse("http://example.com")
reference, _ := url.Parse("/test?a=1&b=2")
endpoint := base.ResolveReference(reference).String()
fmt.Println(endpoint)
req, _ := http.NewRequest("Get", endpoint, nil)
q := req.URL.Query()
q.Add("c", "3&%")
fmt.Println(q)
fmt.Println(q.Encode())
req.URL.RawQuery = q.Encode()
}
実行結果は以下のように表示される。
マップを見ると、クエリパラメータに「c:[3&%]」が追加されていることが分かる。一方エンコードしたクエリパラメータは、「c=3%26%25」のように「&」が「%26」、「%」が「%25」にエンコードされていることが分かる。(URL表記では&は区切り文字なのでそのまま入れることはできない。%も同様)
http.ClientでHTTPリクエストを送信する
作成したHTTPリクエストを使ってGETリクエストを行うにはhttp.Clientという型でクライアントを作る必要がある。
「var client *http.Client = &http.Client{}」というクライアントを宣言し、「clinet.Do(req)」で変数reqのHTTPリクエストを実行し、実行結果を変数respに代入する。
io.ReadAllで内容を読み取ると「http://example.com」の内容が表示される。
(このページはクエリパラメータを渡してもレスポンスに変化がない)
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
base, _ := url.Parse("http://example.com")
reference, _ := url.Parse("/test?a=1&b=2")
endpoint := base.ResolveReference(reference).String()
fmt.Println(endpoint)
req, _ := http.NewRequest("Get", endpoint, nil)
q := req.URL.Query()
q.Add("c", "3&%")
fmt.Println(q)
fmt.Println(q.Encode())
req.URL.RawQuery = q.Encode()
var client *http.Client = &http.Client{}
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP
・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897