Skip to content

HttpRouter

リポジトリ:julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)

Gin のルートコンポーネントは HttpRouter を採用しています。これも軽量で高性能なルートコンポーネントで、コンポーネント全体でわずか 3 つの .go ファイルのみで、コードは非常に簡潔です。主な特徴は以下の通りです。

一対一マッチング:1 つの要求は 0 個または 1 つのルートにのみマッチでき、SEO 最適化に有利です。

パス自動補正:好きな URL スタイルを選択できます。スラッシュが多くても少なくても、自動的にリダイレクトされます。大文字小文字の誤りがある場合も、大文字小文字を無視して正しくリダイレクトされます。

ルートパラメータ自動解析:パスセグメントに名前を付けると、ルーターが動的値を渡します。ルーターの設計により、パスパラメータ解析のオーバーヘッドは非常に低いです。

ゼロガーベジ:ルート割り当てとスケジューリングの過程で、メモリーガーベジは一切生成されません。

RestfulAPI サポート:ルーターの設計は、合理的な階層化された Restful API を促進します。

エラー処理:要求中の例外を処理するエラーハンドラーを設定できます。ルーターはこれをキャッチして記録し、エラーページにリダイレクトします。

基本的な使い方

springboot と同様に、1 つの関数を 1 つの URL にバインドし、1 つのハンドラーに対応させます。

go
package main

import (
   "fmt"
   "github.com/julienschmidt/httprouter"
   "log"
   "net/http"
)

func Hello(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
   fmt.Fprintf(w, "<h1>Hello World!")
}

func main() {
   router := httprouter.New()
   router.GET("/hello", Hello)
   log.Fatal(http.ListenAndServe(":8080", router))
}

その後、ブラウザまたは任意のインターフェーステストツールで 127.0.0.1:8080 にアクセスすると、正しい内容が表示されます。HttpRouter は単にルートのみを行い、実際には引き続き net/http デフォルトコンポーネントを使用しています。gin も同様ですが、カプセル化がより深くなっています。

名前付きパラメータ

go
package main

import (
   "fmt"
   "github.com/julienschmidt/httprouter"
   "log"
   "net/http"
)

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
   fmt.Fprintf(w, "<h1>Hello World!")
}

func main() {
   router := httprouter.New()
   router.GET("/hello:name", Hello)
   log.Fatal(http.ListenAndServe(":8080", router))
}

今回のルートの後に :name が追加されています。name は名前付きパラメータで、httprouter.Params を通じてパラメータスライスにアクセスできます。インデックスまたは ByName(name) を使用してパラメータを取得できます。同様に、http.handlerhttp.handlerFunchttprouter.handler として使用できます。ルート自体がそのインターフェースを実装しています。以下の例の通りです。

go
func Hello(w http.ResponseWriter, r *http.Request) {
    params := httprouter.ParamsFromContext(r.Context())
    //params := r.Context().Value(httprouter.ParamsKey) も可

    fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}

メソッドがバインドするルートが /user/:user の場合、以下の几种の URL のマッチング状況

 /user/gordon              マッチ
 /user/you                 マッチ
 /user/gordon/profile      ノーマッチ
 /user/                    ノーマッチ

/user/new/user/:user を同じ要求メソッドに登録することはできません。各要求メソッドは相互に独立している必要があります。

全パラメータのキャプチャ

2 番目のタイプは全パラメータのキャプチャで、その名の通り、これらはすべてにマッチするため、Pattern の末尾に配置する必要があります。

go
Pattern: /src/*filepath

 /src/                     マッチ
 /src/somefile.go          マッチ
 /src/subdir/somefile.go   マッチ

HttpRouter の動作原理は大量のプレフィックスツリーを構築することです。興味のある方は参照してください:httprouter package - github.com/julienschmidt/httprouter - Go Packages

OPTIONS & CORS

一部の方は、OPTIONS の自動レスポンスを変更し、CORS のプレフライト要求に適応するためにいくつかのレスポンスヘッダーを設定したい場合があります。これらの要件は Router.GlobalOPTIONS ハンドラーを使用して実現できます。

go
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if r.Header.Get("Access-Control-Request-Method") != "" {
        // CORS レスポンスヘッダーを設定
        header := w.Header()
        header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
        header.Set("Access-Control-Allow-Origin", "*")
    }

    // ステータスコード 204 に適応
    w.WriteHeader(http.StatusNoContent)
})

NOT FOUND ハンドラー

TIP

いくつかの問題を避けるために、Router.HandleMethodNotAllowed を無効にする必要がある場合があります。

go
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
  // あなたのロジック
})

基本認証

go
package main

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

  "github.com/julienschmidt/httprouter"
)

func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
  return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    // 基本認証情報を取得
    user, password, hasAuth := r.BasicAuth()

    if hasAuth && user == requiredUser && password == requiredPassword {
      // 要求を指定されたハンドラーに委譲
      h(w, r, ps)
    } else {
      // それ以外の場合、認証を要求
      w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
      http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
    }
  }
}

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
  fmt.Fprint(w, "Not protected!\n")
}

func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
  fmt.Fprint(w, "Protected!\n")
}

func main() {
  user := "gordon"
  pass := "secret!"

  router := httprouter.New()
  router.GET("/", Index)
  router.GET("/protected/", BasicAuth(Protected, user, pass))

  log.Fatal(http.ListenAndServe(":8080", router))
}

Golang学习网由www.golangdev.cn整理维护