HTTPクライアント

HTTPクライアント #

注意事項 #

The Go Playground では外部のサイトへのアクセスを禁止しているのか HTTP クライアントが正常に動作しない。

他の章に合わせて The Go Playground での実行リンクを記載してはいるが、 動作確認したい場合は Go が実行可能な環境にファイルをコピーして go run などで実行すること。

GET リクエストを送信する #

GET リクエストの送信には net/http パッケージの func Get(url string) (resp *Response, err error) 関数を使う。

レスポンスは io.Reader なので io.ReadAll などでコンテンツを読み込む。

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	// リクエストの送信
	res, err := http.Get("http://example.com")
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを読み込む
	body, err := io.ReadAll(res.Body)
	res.Body.Close()

	// ステータスコードの判定
	if res.StatusCode != http.StatusOK {
		log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , io

POST リクエストを送信する #

POST リクエストの送信には net/http パッケージの func Post(url, contentType string, body io.Reader) (resp *Response, err error) 関数を使う。

リクエストのボディは io.Writer なので bytes.Buffer などを使う。

レスポンスは io.Reader なので io.ReadAll などでコンテンツを読み込む。

下記のコードは JSON を POST で送信する例。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	// リクエストボディの作成
	data, err := json.Marshal(map[string]string{
		"key": "value",
	})
	if err != nil {
		log.Fatal(err)
	}
	requestBody := bytes.NewBuffer(data)

	// リクエストの送信
	res, err := http.Post("http://example.com", "application/json", requestBody)
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを読み込む
	body, err := io.ReadAll(res.Body)
	res.Body.Close()

	// ステータスコードの判定
	if res.StatusCode != http.StatusOK {
		log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , io

POST で HTML フォームと同じ形式のデータを送信する #

POST リクエストで HTML のフォームと同じ形式のデータを送信するには net/http パッケージの func PostForm(url string, data url.Values) (resp *Response, err error) を使う。

リクエストのボディは url.Values になる。

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
)

func main() {
	// リクエストボディの作成
	values := url.Values{}
	values.Set("name1", "value1")
	values.Set("name2", "value2")
	values.Set("name3", "value3")

	// リクエストの送信
	res, err := http.PostForm("http://example.com", values)
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを読み込む
	body, err := io.ReadAll(res.Body)
	res.Body.Close()

	// ステータスコードの判定
	if res.StatusCode != http.StatusOK {
		log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , net/url

GET リクエストのヘッダーをカスタマイズする #

リクエストのヘッダーをカスタマイズする場合は http.Request を使ってヘッダーを設定し、http.Client でリクエストの送信をする。

これは http.Get の中で行なっているのと同じ処理である。

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	// リクエストの作成
	// GET の場合はリクエストボディである第三引数を nil にする
	req, err := http.NewRequest("GET", "http://example.com", nil)
	if err != nil {
		log.Fatal(err)
	}

	// ヘッダーの設定
	req.Header.Set("Accept-Encoding", "gzip, deflate")
	req.Header.Set("Accept-Language", "en-us")

	// リクエストの送信
	c := &http.Client{}
	res, err := c.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを読み込む
	body, err := io.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , net/url

POST リクエストのヘッダーをカスタマイズする #

リクエストのヘッダーをカスタマイズする場合は http.Request を使ってヘッダーを設定し、http.Client でリクエストの送信をする。

これは http.Post の中で行なっているのと同じ処理である。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	// リクエストボディの作成
	data, err := json.Marshal(map[string]string{
		"key": "value",
	})
	if err != nil {
		log.Fatal(err)
	}
	requestBody := bytes.NewBuffer(data)

	// リクエストの作成
	req, err := http.NewRequest("POST", "http://example.com", requestBody)
	if err != nil {
		log.Fatal(err)
	}

	// ヘッダーの設定
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept-Language", "en-us")

	// リクエストの送信
	c := &http.Client{}
	res, err := c.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを読み込む
	body, err := io.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", body)
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , net/url

POST で HTML フォームの形式のファイルを送信する #

HTML のフォームでファイルを送っているのと同じ形式で POST リクエストを送信したい場合は、 mime/multipartmultipart.Writer を使ってリクエストボディを作る。

package main

import (
	"bytes"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	// アップロードするファイルを開く
	filename := "hello.txt"
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}

	// リクエストボディの作成準備
	body := &bytes.Buffer{}
	mw := multipart.NewWriter(body)
	fw, err := mw.CreateFormFile("file", filename)

	// リクエストボディへファイルの内容を書き込む
	_, err = io.Copy(fw, file)
	if err != nil {
		log.Fatal(err)
	}

	// リクエストボディの作成終了
	err = mw.Close()
	if err != nil {
		log.Fatal(err)
	}

	// リクエストを送信
	resp, err := http.Post("http://localhost:3000/upload", mw.FormDataContentType(), body)
	if err != nil {
		log.Fatal(err)
	}

	// レスポンスを閉じる
	err = resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: net/http , mime/multipart