简体   繁体   English

重定向返回http:多个响应.WriteHeader调用

[英]Redirects return http: multiple response.WriteHeader calls

I am using Jon Calhoun's Go MVC framework from github. 我正在使用来自github的Jon Calhoun的Go MVC框架

The framework uses julienschmidt/httprouter as its only dependency. 该框架使用julienschmidt / httprouter作为其唯一依赖项。

I have a similar main method as found in the example: 我有一个与示例类似的主要方法:

  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))
    }

I make a post to the login url, and it calls the following method: 我在登录网址中发布了一个帖子,它调用了以下方法:

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))
}

Basically, if the login was not correct I return the same view. 基本上,如果登录不正确,我将返回相同的视图。 If the login is correct I want to redirect to another method in a different controller. 如果登录正确,我想重定向到另一个控制器中的另一个方法。

However when I call http.Redirect(w, r, "/dashboard", 307) , it returns the following error: 但是,当我调用http.Redirect(w, r, "/dashboard", 307) ,它返回以下错误:

http: multiple response.WriteHeader calls  

I'm not sure exactly why this is happening, but I suspect that it has something to do with my listener calling the Perform function, which creates a http.handler, as shown below. 我不确定为什么会这样,但是我怀疑这与我的监听器调用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)
            }

        })
}

Does anyone have any idea how to redirect using this MVC framework? 有谁知道如何使用此MVC框架进行重定向? Or have a one off solution? 还是有一个一次性解决方案?

http.ResponseWriter 's WriteHeader method can only be called once per HTTP response, for obvious reasons: You can only have a single response code, and you can only send the headers once. 每个HTTP响应只能调用一次http.ResponseWriterWriteHeader方法,原因很明显:您只能有一个响应代码,并且只能发送标头一次。

The error you see means that it is called a second time on the same response. 您看到的错误意味着在同一响应上第二次被调用。

Your middleware calls: 您的中间件调用:

        w.WriteHeader(200)

Then your handler also calls: 然后,您的处理程序还会调用:

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

Your middleware should never call WriteHeader , until after the fate of the response is known. 您的中间件永远不要调用WriteHeader ,直到知道响应的命运。

Further, without knowing about your particular MVC framework, it seems possible that after you send the 307 status, then you also tell the MVC framework to render a response, which may also call WriteHeader again. 此外,在不了解特定MVC框架的情况下,似乎有可能在发送307状态之后,您还告诉MVC框架呈现响应,这也可能再次调用WriteHeader

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM