Golang製Web Framework「gin」とjavascriptライブラリ「React」を合わせてウェブサービスを作ることを考えます。
ルーティング部分でちょっと詰まったので覚書き。
ファイルサーバーとしてginを動かす
まずginでファイルを返すにはStatic
を使う。
1 2 3 4 5 6 7 8 9 10 11 |
r:= gin.Default() //フォルダを指定 r.Static("/assets", "./assets") //ファイルシステムを指定 //シングルバイナリにしてる時など r.StaticFS("/assetfs", statikFS) //ファイル単体を指定 r.StaticFile("/some.file", "./assets/favicon.png") |
Reactのルーティングを使わない場合にはこれで問題ない。
ついでにReactから呼び出すAPI部分はわかりやすいようにグループ化しておく。
1 2 3 4 5 |
api := r.Group("/api") { api.GET("/s1", service1) api.GET("/s2/:a/:b", service2) } |
Staticはそのままだとルートアクセスに設定できないが”github.com/gin-gonic/contrib/static”を使って簡単に設定できる。
1 |
r.Use(static.Serve("/", static.LocalFile("./assets", true))) |
これでルートへのアクセスでReactページを返せます。
Reactルーティング
Reactで<Router>
を使っている場合、ルートページから遷移する場合には動作するが、URL直打ちのように直接アクセスすると404が返ってくる。
これはginのルーティングでアクセスエラーになっているせいです。
そこでルーティングが設定されてない場合の動作をNoRoute
で書きます。
1 2 3 4 5 6 7 8 9 10 11 |
folderPath := "./react/build" r.NoRoute(func(c *gin.Context) { _, file := path.Split(c.Request.RequestURI) ext := filepath.Ext(file) //ディレクトリアクセス(ファイル名がない)かパスクエリ(拡張子がない) if file == "" || ext == "" { c.File(folderPath + "/index.html") } else { c.File(folderPath + c.Request.RequestURI) } }) |
ファイルがある場合にはそれを返してファイルがない時はindex.html
を返す。
これで直接アクセス時もReactルーティングに沿った動きになります。
if
文ture
側の404動作はReact側でする必要があるのは注意。
このままだとリンクミスや誤アクセスなどのアクセス全てにindex.html
を返してしまうので、Reactのルーティングに合わせて条件分岐を入れてもいい。
シングルバイナリ化する場合は少し力技ですがこう書けます。
1 2 3 4 |
f, _ := statikFS.Open("/index.html") defer f.Close() b, _ := ioutil.ReadAll(f) c.Data(200, "text/html", b) |
色々なパターンを考えていくとこの辺の処理は結構膨らみそう。
図にすると大体こんな感じの流れだと思います。