GoでHTTPリクエストを作成する方法

提供:Dev Guides
移動先:案内検索

著者は、 Diversity in Tech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

プログラムが別のプログラムと通信する必要がある場合、多くの開発者はHTTPを使用します。 Goの強みの1つはその標準ライブラリの幅広さであり、HTTPも例外ではありません。 Go net / http パッケージは、 HTTPサーバーの作成をサポートするだけでなく、クライアントとしてHTTPリクエストを作成することもできます。

このチュートリアルでは、HTTPサーバーに対していくつかのタイプのHTTPリクエストを作成するプログラムを作成します。 まず、デフォルトのGoHTTPクライアントを使用してGETリクエストを作成します。 次に、プログラムを拡張して、本文を使用してPOSTリクエストを作成します。 最後に、POSTリクエストをカスタマイズしてHTTPヘッダーを含め、リクエストに時間がかかりすぎる場合にトリガーされるタイムアウトを追加します。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • バージョン1.16以降をインストールしてください。 これを設定するには、オペレーティングシステムのGoチュートリアルをインストールする方法に従ってください。
  • GoでHTTPサーバーを作成した経験。これはチュートリアルGoでHTTPサーバーを作成する方法にあります。
  • ゴルーチンと読書チャンネルに精通していること。 詳細については、チュートリアルGoで複数の関数を同時に実行する方法を参照してください。
  • HTTPリクエストがどのように構成および送信されるかを理解することをお勧めします。

GETリクエストを行う

Go net / http パッケージには、クライアントとして使用するためのいくつかの異なる方法があります。 http.Get などの機能を備えた一般的なグローバルHTTPクライアントを使用して、URLと本文のみでHTTP GETリクエストをすばやく作成するか、を作成できます。 http.Request を使用して、個々のリクエストの特定の側面のカスタマイズを開始します。 このセクションでは、http.Getを使用してHTTPリクエストを作成する初期プログラムを作成してから、デフォルトのHTTPクライアントでhttp.Requestを使用するように更新します。

http.Getを使用してリクエストを行う

プログラムの最初の反復では、http.Get関数を使用して、プログラムで実行しているHTTPサーバーにリクエストを送信します。 http.Get関数は、リクエストを行うためにプログラムで追加のセットアップを行う必要がないため便利です。 クイックリクエストを1回行う必要がある場合は、http.Getが最適なオプションです。

プログラムの作成を開始するには、プログラムのディレクトリを保持するためのディレクトリが必要です。 このチュートリアルでは、projectsという名前のディレクトリを使用します。

まず、projectsディレクトリを作成し、次の場所に移動します。

mkdir projects
cd projects

次に、プロジェクトのディレクトリを作成し、そこに移動します。 この場合、ディレクトリhttpclientを使用します。

mkdir httpclient
cd httpclient

httpclientディレクトリ内で、nanoまたはお気に入りのエディタを使用して、main.goファイルを開きます。

nano main.go

main.goファイルで、次の行を追加することから始めます。

main.go

package main

import (
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"
)

const serverPort = 3333

packageという名前mainを追加して、プログラムを実行可能なプログラムとしてコンパイルし、importステートメントを使用するさまざまなパッケージに含めます。このプログラム。 その後、値3333serverPortというconstを作成します。これは、HTTPサーバーがリッスンしているポートおよびHTTPクライアントがリッスンするポートとして使用します。に接続します。

次に、main.goファイルにmain関数を作成し、HTTPサーバーを起動するためのゴルーチンを設定します。

main.go

...
func main() {
    go func() {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            fmt.Printf("server: %s /\n", r.Method)
        })
        server := http.Server{
            Addr:    fmt.Sprintf(":%d", serverPort),
            Handler: mux,
        }
        if err := server.ListenAndServe(); err != nil {
            if !errors.Is(err, http.ErrServerClosed) {
                fmt.Printf("error running http server: %s\n", err)
            }
        }
    }()

    time.Sleep(100 * time.Millisecond)

HTTPサーバーは、ルート/パスが要求されるたびに、fmt.Printfを使用して着信要求に関する情報を出力するように設定されています。 serverPortでリッスンするようにも設定されています。 最後に、サーバーゴルーチンを起動すると、プログラムはtime.Sleepを短時間使用します。 このスリープ時間により、HTTPサーバーは、起動して次に行う要求への応答の提供を開始するために必要な時間を確保できます。

ここで、main関数でも、fmt.Sprintfを使用してリクエストURLを設定し、http://localhostホスト名とサーバーがリッスンしているserverPort値を組み合わせます。 次に、http.Getを使用して、以下に示すように、そのURLにリクエストを送信します。

main.go

...
    requestURL := fmt.Sprintf("http://localhost:%d", serverPort)
    res, err := http.Get(requestURL)
    if err != nil {
        fmt.Printf("error making http request: %s\n", err)
        os.Exit(1)
    }

    fmt.Printf("client: got response!\n")
    fmt.Printf("client: status code: %d\n", res.StatusCode)
}

http.Get関数が呼び出されると、GoはデフォルトのHTTPクライアントを使用して指定されたURLにHTTPリクエストを送信し、http.Responseまたはerror値を返します。リクエストが失敗した場合。 リクエストが失敗した場合、エラーが出力され、os.Exitを使用してエラーコード1でプログラムが終了します。 リクエストが成功すると、プログラムはレスポンスと受け取ったHTTPステータスコードを受け取ったことを出力します。

完了したら、ファイルを保存して閉じます。

プログラムを実行するには、go runコマンドを使用して、main.goファイルをプログラムに提供します。

go run main.go

次の出力が表示されます。

Outputserver: GET /
client: got response!
client: status code: 200

出力の最初の行で、サーバーは、クライアントから/パスのGET要求を受信したことを出力します。 次に、次の2行は、クライアントがサーバーから応答を受け取り、応答のステータスコードが200であったことを示しています。

http.Get関数は、このセクションで行ったような迅速なHTTPリクエストに役立ちます。 ただし、http.Requestには、リクエストをカスタマイズするための幅広いオプションが用意されています。

http.Requestを使用してリクエストを行う

http.Getとは対照的に、http.Request関数を使用すると、HTTPメソッドと要求されているURLだけでなく、要求をより細かく制御できます。 まだ追加機能を使用することはありませんが、http.Requestを使用することで、このチュートリアルの後半でそれらのカスタマイズを追加できるようになります。

コードでは、最初の更新は、fmt.Fprintfを使用して偽のJSONデータ応答を返すようにHTTPサーバーハンドラーを変更することです。 これが完全なHTTPサーバーである場合、このデータはGoの encoding /jsonパッケージを使用して生成されます。 GoでのJSONの使用について詳しく知りたい場合は、GoでJSONを使用する方法チュートリアルを利用できます。 さらに、このアップデートの後半で使用するためのインポートとしてio/ioutilも含める必要があります。

次に、main.goファイルを再度開き、プログラムを更新して、以下に示すようにhttp.Requestの使用を開始します。

main.go

package main

import (
    ...
    "io/ioutil"
    ...
)

...

func main() {
    ...
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("server: %s /\n", r.Method)
        fmt.Fprintf(w, `{"message": "hello!"}`)
    })
    ...

ここで、HTTPリクエストコードを更新して、http.Getを使用してサーバーにリクエストを送信する代わりに、http.NewRequestおよびhttp.DefaultClientDoメソッドを使用するようにします。 :

main.go

...
    requestURL := fmt.Sprintf("http://localhost:%d", serverPort)
    req, err := http.NewRequest(http.MethodGet, requestURL, nil)
    if err != nil {
        fmt.Printf("client: could not create request: %s\n", err)
        os.Exit(1)
    }

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Printf("client: error making http request: %s\n", err)
        os.Exit(1)
    }

    fmt.Printf("client: got response!\n")
    fmt.Printf("client: status code: %d\n", res.StatusCode)

    resBody, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Printf("client: could not read response body: %s\n", err)
        os.Exit(1)
    }
    fmt.Printf("client: response body: %s\n", resBody)
}

このアップデートでは、http.NewRequest関数を使用してhttp.Request値を生成するか、値を作成できない場合はエラーを処理します。 ただし、http.Get関数とは異なり、http.NewRequest関数はサーバーにHTTPリクエストをすぐに送信しません。 リクエストはすぐには送信されないため、送信する前にリクエストに必要な変更を加えることができます。

http.Requestを作成して構成したら、http.DefaultClientDoメソッドを使用してサーバーにリクエストを送信します。 http.DefaultClientの値は、GoのデフォルトのHTTPクライアントであり、http.Getで使用しているものと同じです。 ただし、今回は、http.Requestを送信するように直接使用しています。 HTTPクライアントのDoメソッドは、http.Get関数から受け取ったのと同じ値を返すため、同じ方法で応答を処理できます。

リクエスト結果を出力したら、 ioutil.ReadAll 関数を使用して、HTTP応答のBodyを読み取ります。 Bodyio.ReadCloser値であり、io.Readerio.Closerの組み合わせであり、本体のio.Reader値から読み取ることができるものを使用するデータ。 ioutil.ReadAll関数は、io.Readerからデータの最後に到達するか、errorに遭遇するまで読み取るため、便利です。 次に、fmt.Printfを使用して印刷できる[]byte値、または検出したerror値としてデータを返します。

更新したプログラムを実行するには、変更を保存してgo runコマンドを使用します。

go run main.go

今回は、出力は以前と非常によく似ているはずですが、次の1つが追加されています。

Outputserver: GET /
client: got response!
client: status code: 200
client: response body: {"message": "hello!"}

最初の行では、サーバーが/パスへのGET要求をまだ受信していることがわかります。 クライアントはサーバーから200応答も受信しますが、サーバーの応答のBodyも読み取って出力します。 より複雑なプログラムでは、サーバーから本文として受け取った{"message": "hello!"}値を取得し、 encoding /jsonパッケージを使用してJSONとして処理できます。

このセクションでは、さまざまな方法でHTTPリクエストを行ったHTTPサーバーを使用してプログラムを作成しました。 まず、http.Get関数を使用して、サーバーのURLのみを使用してサーバーにGET要求を行いました。 次に、http.NewRequestを使用してhttp.Request値を作成するようにプログラムを更新しました。 それが作成されたら、GoのデフォルトのHTTPクライアントであるhttp.DefaultClientDoメソッドを使用してリクエストを行い、http.ResponseBodyを出力に出力します。 。

ただし、HTTPプロトコルは、プログラム間の通信にGET要求以上のものを使用します。 GETリクエストは、他のプログラムから情報を受信する場合に役立ちますが、プログラムからサーバーに情報を送信する場合は、別のHTTPメソッドであるPOSTメソッドを使用できます。 。

POSTリクエストの送信

REST API では、GETリクエストはサーバーから情報を取得するためにのみ使用されるため、プログラムがREST APIに完全に参加するには、プログラムが[X200Xの送信もサポートする必要があります。 ]リクエスト。 POSTリクエストは、GETリクエストのほぼ逆であり、クライアントはリクエストの本文でサーバーにデータを送信します。

このセクションでは、プログラムを更新して、GETリクエストではなくPOSTリクエストとしてリクエストを送信します。 POSTリクエストにはリクエストの本文が含まれ、サーバーを更新して、クライアントからのリクエストに関する詳細情報を出力します。

これらの更新を開始するには、main.goファイルを開き、使用するいくつかの新しいパッケージをimportステートメントに追加します。

main.go

...

import (
    "bytes"
    "errors"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "strings"
    "time"
)

...

次に、サーバーハンドラー関数を更新して、クエリ文字列値、ヘッダー値、リクエスト本文など、着信するリクエストに関するさまざまな情報を出力します。

main.go

...
  mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      fmt.Printf("server: %s /\n", r.Method)
      fmt.Printf("server: query id: %s\n", r.URL.Query().Get("id"))
      fmt.Printf("server: content-type: %s\n", r.Header.Get("content-type"))
      fmt.Printf("server: headers:\n")
      for headerName, headerValue := range r.Header {
          fmt.Printf("\t%s = %s\n", headerName, strings.Join(headerValue, ", "))
      }

      reqBody, err := ioutil.ReadAll(r.Body)
      if err != nil {
             fmt.Printf("server: could not read request body: %s\n", err)
      }
      fmt.Printf("server: request body: %s\n", reqBody)

      fmt.Fprintf(w, `{"message": "hello!"}`)
  })
...

サーバーのHTTPリクエストハンドラーに対するこのアップデートでは、受信するリクエストに関する情報を確認するために、さらに役立つfmt.Printfステートメントをいくつか追加します。 r.URL.Query().Getを使用してidという名前のクエリ文字列値を取得し、r.Header.Getを使用してcontent-typeという名前のヘッダーの値を取得します。 また、forループとr.Headerを使用して、サーバーが受信した各HTTPヘッダーの名前と値を出力します。 この情報は、クライアントまたはサーバーが期待どおりに動作していない場合の問題のトラブルシューティングに役立ちます。 最後に、ioutil.ReadAll関数を使用して、r.BodyのHTTPリクエストの本文を読み取りました。

サーバーハンドラー関数を更新した後、main関数のリクエストコードを更新して、リクエスト本文を含むPOSTリクエストを送信するようにします。

main.go

...
 time.Sleep(100 * time.Millisecond)
    
 jsonBody := []byte(`{"client_message": "hello, server!"}`)
 bodyReader := bytes.NewReader(jsonBody)

 requestURL := fmt.Sprintf("http://localhost:%d?id=1234", serverPort)
 req, err := http.NewRequest(http.MethodPost, requestURL, bodyReader)
...

main関数の要求に対する更新で、定義している新しい値の1つはjsonBody値です。 この例では、値は標準のstringではなく[]byteとして表されます。これは、encoding/jsonパッケージを使用してJSONデータをエンコードすると、[X172X stringの代わりにバック。

次の値であるbodyReaderは、jsonBodyデータをラップするbytes.Readerです。 http.Request本体では、値がio.Readerである必要があり、jsonBody[]byte値はio.Readerを実装していないため、それ自体をリクエストボディとして使用することはできません。 bytes.Reader値は、そのio.Readerインターフェイスを提供するために存在するため、jsonBody値を要求の本文として使用できます。

requestURL値も更新され、id=1234クエリ文字列値が含まれるようになりました。これは主に、クエリ文字列値を他の標準URLコンポーネントとともにリクエストURLに含める方法を示すためです。

最後に、http.NewRequest関数呼び出しがPOSTメソッドとhttp.MethodPostを使用するように更新され、nilの最後のパラメーターを更新することでリクエスト本文が含まれます。本文はbodyReader、JSONデータio.Readerです。

変更を保存したら、go runを使用してプログラムを実行できます。

go run main.go

追加情報を表示するためのサーバーの更新により、出力は以前より長くなります。

Outputserver: POST /
server: query id: 1234
server: content-type: 
server: headers:
        Accept-Encoding = gzip
        User-Agent = Go-http-client/1.1
        Content-Length = 36
server: request body: {"client_message": "hello, server!"}
client: got response!
client: status code: 200
client: response body: {"message": "hello!"}

サーバーからの最初の行は、リクエストがPOSTリクエストとして/パスに送信されていることを示しています。 2行目は、リクエストのURLに追加したidクエリ文字列値の1234値を示しています。 3行目は、クライアントが送信したContent-Typeヘッダーの値を示しています。このヘッダーは、このリクエストでは空になっています。

4行目は、上記の出力とは少し異なる場合があります。 Goでは、rangeを使用して反復処理した場合、map値の順序は保証されないため、r.Headersのヘッダーが異なる順序で出力される場合があります。 使用しているGoのバージョンによっては、上記のものとは異なるUser-Agentバージョンが表示される場合もあります。

最後に、出力の最後の変更は、サーバーがクライアントから受信したリクエスト本文を表示していることです。 次に、サーバーはencoding/jsonパッケージを使用して、クライアントが送信したJSONデータを解析し、応答を作成できます。

このセクションでは、GETリクエストの代わりにHTTPPOSTリクエストを送信するようにプログラムを更新しました。 また、bytes.Readerによって読み取られる[]byteデータを含むリクエスト本文を送信するようにプログラムを更新しました。 最後に、サーバーハンドラー関数を更新して、HTTPクライアントが行っている要求に関する詳細情報を出力しました。

通常、HTTPリクエストでは、クライアントまたはサーバーは、本文で送信しているコンテンツのタイプを相手に通知します。 ただし、最後の出力で見たように、HTTPリクエストには、本文のデータを解釈する方法をサーバーに指示するContent-Typeヘッダーが含まれていませんでした。 次のセクションでは、送信するデータの種類をサーバーに通知するためのContent-Typeヘッダーの設定など、HTTPリクエストをカスタマイズするためのいくつかの更新を行います。

HTTPリクエストのカスタマイズ

時間の経過とともに、HTTP要求と応答は、クライアントとサーバー間でさまざまなデータを送信するために使用されてきました。 ある時点で、HTTPクライアントは、HTTPサーバーから受信しているデータがHTMLであり、正しい可能性が高いと想定する可能性があります。 ただし、HTML、JSON、音楽、ビデオ、またはその他の任意の数のデータ型である可能性があります。 HTTPを介して送信されるデータに関する詳細情報を提供するために、プロトコルにはHTTPヘッダーが含まれており、それらの重要なヘッダーの1つはContent-Typeヘッダーです。 このヘッダーは、サーバー(またはデータの方向によってはクライアント)に、受信しているデータを解釈する方法を指示します。

このセクションでは、プログラムを更新してHTTPリクエストにContent-Typeヘッダーを設定し、サーバーがJSONデータを受信していることを認識できるようにします。 また、Goのデフォルトのhttp.DefaultClient以外のHTTPクライアントを使用するようにプログラムを更新して、リクエストの送信方法をカスタマイズできるようにします。

これらの更新を行うには、main.goファイルを再度開き、main関数を次のように更新します。

main.go

...

  req, err := http.NewRequest(http.MethodPost, requestURL, bodyReader)
  if err != nil {
         fmt.Printf("client: could not create request: %s\n", err)
         os.Exit(1)
  }
  req.Header.Set("Content-Type", "application/json")

  client := http.Client{
     Timeout: 30 * time.Second,
  }

  res, err := client.Do(req)
  if err != nil {
      fmt.Printf("client: error making http request: %s\n", err)
      os.Exit(1)
  }

...

このアップデートでは、req.Headerを使用してhttp.Requestヘッダーにアクセスし、リクエストのContent-Typeヘッダーの値をapplication/jsonに設定します。 application/jsonメディアタイプは、メディアタイプのリストでJSONのメディアタイプとして定義されています。 このように、サーバーはリクエストを受信すると、本文をJSONとして解釈し、たとえばXMLとして解釈しないことを認識します。

次の更新は、client変数に独自のhttp.Clientインスタンスを作成することです。 このクライアントでは、Timeoutの値を30秒に設定します。 これは、クライアントで行われたすべての要求が放棄され、30秒後に応答の受信を停止することを示しているため重要です。 Goのデフォルトのhttp.DefaultClientはタイムアウトを指定していないため、そのクライアントを使用してリクエストを行うと、応答を受信するか、サーバーによって切断されるか、プログラムが終了するまで待機します。 このように応答を待っているリクエストがたくさんある場合は、コンピューターで大量のリソースを使用している可能性があります。 Timeout値を設定すると、定義した時間までにリクエストが待機する時間が制限されます。

最後に、client変数のDoメソッドを使用するようにリクエストを更新しました。 ずっとhttp.Client値でDoを呼び出しているので、ここで他の変更を行う必要はありません。 GoのデフォルトのHTTPクライアントであるhttp.DefaultClientは、デフォルトで作成されるhttp.Clientにすぎません。 したがって、http.Getを呼び出すと、関数はDoメソッドを呼び出し、http.DefaultClientを使用するようにリクエストを更新すると、その[を使用していました。 X162X]直接。 現在の唯一の違いは、今回使用しているhttp.Client値を作成したことです。

次に、ファイルを保存し、go runを使用してプログラムを実行します。

go run main.go

出力は前の出力と非常に似ているはずですが、コンテンツタイプに関する詳細情報が含まれています。

Outputserver: POST /
server: query id: 1234
server: content-type: application/json
server: headers:
        Accept-Encoding = gzip
        User-Agent = Go-http-client/1.1
        Content-Length = 36
        Content-Type = application/json
server: request body: {"client_message": "hello, server!"}
client: got response!
client: status code: 200
client: response body: {"message": "hello!"}

サーバーからcontent-typeの値があり、Content-Typeヘッダーがクライアントから送信されていることがわかります。 これは、JSONとXMLAPIの両方を同時に提供する同じHTTPリクエストパスを持つことができる方法です。 リクエストのコンテンツタイプを指定することにより、サーバーとクライアントはデータを異なる方法で解釈できます。

ただし、この例では、構成したクライアントタイムアウトはトリガーされません。 リクエストに時間がかかりすぎてタイムアウトがトリガーされたときに何が起こるかを確認するには、main.goファイルを開き、time.Sleep関数呼び出しをHTTPサーバーハンドラー関数に追加します。 次に、time.Sleepを指定したタイムアウトより長く持続させます。 この場合、35秒間設定します。

main.go

...

func main() {
    go func() {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            ... 
            fmt.Fprintf(w, `{"message": "hello!"}`)
            time.Sleep(35 * time.Second)
        })
        ...
    }()
    ...
}

次に、変更を保存し、go runを使用してプログラムを実行します。

go run main.go

今回実行すると、HTTPリクエストが終了するまで終了しないため、以前よりも終了に時間がかかります。 time.Sleep(35 * time.Second)を追加したため、HTTPリクエストは30秒のタイムアウトに達するまで完了しません。

Outputserver: POST /
server: query id: 1234
server: content-type: application/json
server: headers:
        Content-Type = application/json
        Accept-Encoding = gzip
        User-Agent = Go-http-client/1.1
        Content-Length = 36
server: request body: {"client_message": "hello, server!"}
client: error making http request: Post "http://localhost:3333?id=1234": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
exit status 1

このプログラム出力では、サーバーがリクエストを受信して処理したことがわかりますが、time.Sleep関数呼び出しがあるHTTPハンドラー関数の最後に到達すると、サーバーは35秒間スリープを開始しました。 同時に、HTTPリクエストのタイムアウトがカウントダウンされ、HTTPリクエストが終了する前に30秒の制限に達します。 これにより、client.Doメソッド呼び出しが失敗し、context deadline exceededエラーが発生します。これは、要求の30秒の期限が過ぎたためです。 次に、os.Exit(1)を使用して、プログラムは1の障害ステータスコードで終了します。

このセクションでは、Content-Typeヘッダーを追加して、HTTPリクエストをカスタマイズするようにプログラムを更新しました。 また、プログラムを更新して、30秒のタイムアウトで新しいhttp.Clientを作成し、そのクライアントを使用してHTTPリクエストを作成しました。 また、HTTPリクエストハンドラーにtime.Sleepを追加して、30秒のタイムアウトをテストしました。 最後に、多くのリクエストが永久にアイドリングする可能性を回避したい場合は、タイムアウトを設定して独自のhttp.Client値を使用することが重要である理由もわかりました。

結論

このチュートリアルでは、HTTPサーバーを使用して新しいプログラムを作成し、Goのnet/httpパッケージを使用してそのサーバーにHTTPリクエストを送信しました。 まず、http.Get関数を使用して、GoのデフォルトのHTTPクライアントを使用してサーバーにGETリクエストを送信しました。 次に、http.NewRequesthttp.DefaultClientDoメソッドを使用して、GETリクエストを作成しました。 次に、リクエストを更新して、bytes.NewReaderを使用して本文を含むPOSTリクエストにしました。 最後に、http.RequestHeaderフィールドでSetメソッドを使用して、リクエストのContent-Typeヘッダーを設定し、 Goのデフォルトクライアントを使用する代わりに、独自のHTTPクライアントを作成してリクエストの期間。

net / http パッケージには、このチュートリアルで使用した機能以上のものが含まれています。 また、http.Get関数と同様に、POSTリクエストを行うために使用できるhttp.Post関数も含まれています。 このパッケージは、他の機能の中でも特に、Cookieの保存と取得をサポートしています。

このチュートリアルは、 DigitalOcean How to Code inGoシリーズの一部でもあります。 このシリーズでは、Goの初めてのインストールから、言語自体の使用方法まで、Goに関する多くのトピックを取り上げています。