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

I am using Jon Calhoun's Go MVC framework from github.

The framework uses julienschmidt/httprouter as its only dependency.

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: 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.

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? Or have a one off solution?

doucu7525
doucu7525 引用的代码会在检查错误并尝试使用http.Error发出错误状态之前立即调用w.WriteHeader(200),无论处理程序本身尝试发送的任何其他状态代码如何,该错误都会始终失败。必须使用WriteHeader调用才能正常工作。
接近 3 年之前 回复
duanpin2009
duanpin2009 在传递给处理程序之前,在中间件中设置响应状态是没有意义的。如果在处理程序中遇到问题怎么办?现在您的状态需要更改,但是您已经写了200...
接近 3 年之前 回复

1个回答



http.ResponseWriter WriteHeader </ code>方法在每个HTTP响应中只能调用一次,原因很明显:您只能有一个响应代码,并且只能发送一次标头。 </ p>

您看到的错误意味着它在相同的响应上第二次被调用。</ p>

您的中间件调用:</ p>
\ n

  w.WriteHeader(200)
</ code> </ pre>

然后您的处理程序也会调用:</ p>

   http.Redirect(w,r,“ / dashboard”,307)
log.Println(“ -----”)
返回views.Dashboard.Index.Render(w,login,helpers.AcceptsGzip(r))\ n </ code> </ pre>

您的中间件永远不要调用 WriteHeader </ code>,直到知道响应的命运为止。</ p>

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

展开原文

原文

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.

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.

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.

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问