技術向上

プログラミングの学び、気になるテクノロジーやビジネストレンドを発信

Redirects【Go】

http.Redirect()

303、307の例をお見せします。
記述内容が異なるのは、http.Redirect()の第4引数のみです。

templateであるindex.gohtmlです。
formのaction属性に「/bar」を指定します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="POST" action="/bar">
    <input type="text" name="fname">
    <input type="submit">
</form>

</body>
</html>


main.goです。

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseGlob("templates/*"))
}

func main() {
    http.HandleFunc("/", foo)    // 「/」にアクセスしたら、fooを実行
    http.HandleFunc("/bar", bar)    // 「/bar」にアクセスしたら、barを実行
    http.HandleFunc("/barred", barred)    // 「/barred」にアクセスしたら、barredを実行
    http.Handle("/favicon.ico", http.NotFoundHandler())
    http.ListenAndServe(":8080", nil)
}

func foo(w http.ResponseWriter, req *http.Request) {
    fmt.Println("Your request method at foo: ", req.Method)
}

func bar(w http.ResponseWriter, req *http.Request) {
    fmt.Println("Your request method at bar: ", req.Method)
    // 下記いずれかを使用  
        http.Redirect(w, req, "/", http.StatusSeeOther)    // 303
        http.Redirect(w, req, "/", http.StatusTemporaryRedirect)    // 307
}

func barred(w http.ResponseWriter, req *http.Request) {
    fmt.Println("Your request method at barred: ", req.Method)
    err := tpl.ExecuteTemplate(w, "index.gohtml", nil)    // templateを指定し実行
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}


303の場合、出力結果は下記の通りです。

Your request method at barred:  GET
Your request method at bar:  POST
Your request method at foo:  GET    // POSTからGETへ変更される


307の場合、出力結果は下記の通りです。

Your request method at barred:  GET
Your request method at bar:  POST
Your request method at foo:  POST    // POSTのまま


続いて301の例をお見せします。
301は恒久的な移転ですので、templateは用意せず、
URL入力により「/bar」にアクセスしたら、「/」へリダイレクトさせます。

func main() {
    http.HandleFunc("/", foo)
    http.HandleFunc("/bar", bar)
    http.Handle("/favicon.ico", http.NotFoundHandler())
    http.ListenAndServe(":8080", nil)
}

func foo(w http.ResponseWriter, req *http.Request) {
    fmt.Println("Your request method at foo: ", req.Method)
}

func bar(w http.ResponseWriter, req *http.Request) {
    fmt.Println("Your request method at bar: ", req.Method)
    http.Redirect(w, req, "/", http.StatusMovedPermanently)
}


初回実行時の出力結果は次の通りです。

Your request method at bar:  GET
Your request method at foo:  GET


初回実行時のキャッシュがある前提での、2回目以降の出力結果は次の通りです。

Your request method at foo:  GET

ブラウザがMoved Permanentlyを記憶しているので、bar関数は実行されません。

WriteHeader()

http.Redirect()は、次のように書き換えることができます。

func bar(w http.ResponseWriter, req *http.Request) {
    ...
    w.Header().Set("Location", "/")
    w.WriteHeader(http.StatusMovedPermanently)
}

http.ResponseWriter.WriteHeader()で、エラーのステータスコード書き込みます。
そして事前に移動先である、header情報の「Location」に移動先のURLをセットします。