-1

我正在使用来自 github的 Jon Calhoun 的 Go MVC 框架。

该框架使用julienschmidt/httprouter作为其唯一依赖项。

我有一个与示例中类似的主要方法:

  func main() {
        //register routes
        router := httprouter.New()

        //default
        router.GET("/", controllers.Login.Perform(controllers.Login.Index))

        //login
        router.GET("/login", controllers.Login.Perform(controllers.Login.Login))
        router.POST("/login", controllers.Login.Perform(controllers.Login.PostLogin))

        //dashboard
        router.GET("/dashboard", controllers.Dashboard.Perform(controllers.Dashboard.Index))


        //listen and handle requests
        log.Fatal(http.ListenAndServe(":"+helpers.ReadConfig("port_http"), router))
    }

我在登录 url 上发了一个帖子,它调用了以下方法:

func (self LoginController) PostLogin(w http.ResponseWriter, r *http.Request, ps httprouter.Params) error {
    //create our api url
    var url = helpers.ReadConfig("api") + "login"
    //fill model to post
    login := models.LoginModel{
        Password: r.FormValue("password"),
        Email:    r.FormValue("username"),
    }
    //render json from model
    bytes, err := json.Marshal(login)
    if err != nil {
        panic(err)
    }
    //post to the API helpers
    var resp = helpers.ApiPost(url, r, string(bytes))
    //check response if successful
    if resp.Code != constants.ApiResp_Success {
        //TODO: Handle API Errors
        login.Password = ""
        errors := make(map[int]string)
        errors[1] = "Please provide valid credntials."
        login.Common = models.CommonModel{
            ErrorList: errors,
        }
        return views.Login.Index.Render(w, login, helpers.AcceptsGzip(r))
    }


    log.Println("---Redirect--")
    http.Redirect(w, r, "/dashboard", 307)
    log.Println("-----")
    return views.Dashboard.Index.Render(w, login, helpers.AcceptsGzip(r))
}

基本上,如果登录不正确,我会返回相同的视图。如果登录正确,我想重定向到不同控制器中的另一种方法。

但是,当我调用时http.Redirect(w, r, "/dashboard", 307),它会返回以下错误:

http: multiple response.WriteHeader calls  

我不确定为什么会发生这种情况,但我怀疑这与我的侦听器调用 Perform 函数有关,该函数创建了一个 http.handler,如下所示。

func (c *Controller) Perform(a Action) httprouter.Handle {
    return httprouter.Handle(
        func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
            //set response headers
            //TODO: set appropriate responce headers
            w.Header().Set("Access-Control-Allow-Origin", "*")
            w.Header().Set("Cache-Control", "public, max-age=0")
            w.Header().Set("Token", "NOT-A-VALID-TOKEN")
            w.WriteHeader(200)
            if err := a(w, r, ps); err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
            }

        })
}

有谁知道如何使用这个 MVC 框架进行重定向?或者有一个一次性的解决方案?

4

1 回答 1

4

http.ResponseWriterWriteHeader方法每个 HTTP 响应只能调用一次,原因很明显:您只能有一个响应代码,并且您只能发送一次标头。

您看到的错误意味着它在同一响应中被第二次调用。

您的中间件调用:

        w.WriteHeader(200)

然后您的处理程序还调用:

http.Redirect(w, r, "/dashboard", 307)
log.Println("-----")
return views.Dashboard.Index.Render(w, login, helpers.AcceptsGzip(r))

WriteHeader在知道响应的命运之前,您的中间件不应该调用。

此外,在不了解您的特定 MVC 框架的情况下,似乎有可能在您发送307状态后,您还告诉 MVC 框架呈现响应,该响应也可能WriteHeader再次调用。

于 2017-08-24T20:22:43.330 回答