go言語で、リクエストヘッダーを表示するだけのサーバを開発した

f:id:shogonir:20191202195845p:plain

目次

  1. はじめに
  2. go言語でサーバを実装する方法
  3. リクエストのパスを取得する方法
  4. リクエストのヘッダを取得する方法
  5. 動作確認
  6. さいごに

1. はじめに

たまに「このリクエストってどんなヘッダが付いてるんだ?」っておもう時ありませんか?
自分の場合はすでに運用されているサーバが、ログにリクエストヘッダが出ない設定なっていた時です。

というわけでサクッとサーバアプリケーションを開発したかったのでgo言語を選択しました。
go言語の標準パッケージ net/http を使えば簡単にサーバを開発できます。
リポジトリはこちら。

github.com

 

まずは最低限サーバアプリケーションを開発する方法から紹介します。

2. go言語でサーバを実装する方法

まずは特定のパスでリクエストが来た時に実行される処理を登録します。
登録したい処理は、関数として実装します。

引数は第一引数が http.ResponseWriter 型で、第二引数が *http.Request 型です。
この第一引数にたいして書き込みを行うことでレスポンスを構成していきます。

たとえば "ok" を返すだけだったら次のような関数を実装します。

 

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "ok")
}

 

次にこのハンドラーをリクエストパスに紐付けます。
下記のソースコードの通りに書くだけでサーバが起動します。
ポート番号が7999で、 /gora/ から始まるパスに来たら hander 関数が実行されます。

 

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "ok")
}

func main() {
    http.HandleFunc("/gora/", handler)

    err := http.ListenAndServe(":7999", nil)
    if err != nil {
        fmt.Println(err)
    }
}

 

3. リクエストのパスを取得する方法

リクエストのパスは、 http.Request 型のインスタンスから取得することができます。
.RequestURI とすると、ポート番号より後のURIが取得できます。

http://localhost:7999/gora/ping とリクエストした時は、
.RequestURI/gora/ping になります。

4. リクエストのヘッダを取得する方法

リクエストヘッダも http.Request 型のインスタンスから取得することができます。
.Header とすると、リクエストヘッダを map[string][]string のような型です。

5. 動作確認

最終的なソースコードは下記のようになりました。

 

package main

import (
    "flag"
    "fmt"
    "net/http"
    "strconv"
    "time"
)

func strfNow() string {
    now := time.Now()
    const layout = "2006-01-02 15:04:05"
    return now.Format(layout)
}

func suffix(iter int, length int) string {
    if iter == length {
        return "\n"
    } else {
        return ",\n"
    }
}

func displayHeaders(headers http.Header) {
    fmt.Println("\"headers\": {")
    iter, length := 0, len(headers)
    for key, value := range headers {
        iter++
        fmt.Printf("    \"" + key + "\":\"" + value[0] + "\"" + suffix(iter, length))
    }
    fmt.Println("}")
    fmt.Println()
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Println(strfNow() + " " + r.RequestURI)

    displayHeaders(r.Header)

    fmt.Fprint(w, "ok")
}

func main() {

    port := flag.Int("port", 7999, "listen port number")
    flag.Parse()

    fmt.Println()
    fmt.Println("'gora' has started.")
    fmt.Printf("listening: ':%d/gora/*'\n\n", *port)

    http.HandleFunc("/gora/", handler)

    err := http.ListenAndServe(":"+strconv.Itoa(*port), nil)
    if err != nil {
        fmt.Println(err)
    }
}

 

完成したので動作確認を行いたいなと思います。
ポート番号を8000に指定してサーバを起動してみます。

 

$ go run gora.go --port 8000

'gora' has started.
listening: ':8000/gora/*'

 

別のターミナルでリクエストを送ってみます。

 

$ curl "http://localhost:8000/gora/ping"
ok

 

レスポンスボディに ok が返ってきているのがわかります。
その時 gora の方のターミナルにはリクエストヘッダが表示されています。

 

2019-12-02 19:35:43 /gora/ping
"headers": {
    "User-Agent":"curl/7.64.1",
    "Accept":"*/*"
}

 

6 さいごに

今回はgo言語でサーバアプリケーションを実装してみました。
使ってみて、go言語の net/http が非常に優秀なので、
ちょっとしたサーバ開発にはすごくおすすめです。

しかも別の環境で動かしたくなった時もgoなら安心です。
みなさんもgoで何かを開発してみてはいかがでしょうか。