简体   繁体   中英

Golang: redirect twice and cause http: multiple response.WriteHeader calls

I have a very weird output ... let me post my code first then I will explain:

Under main function I declared

manageMux.HandleFunc("/info", info)

first I log in and redirect from "/login" to page "/":

func login(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
        t, err := template.ParseFiles("manage/login.html")
        checkError(err)
        t.Execute(w, nil)
    } else { //POST
        r.ParseForm()
        //do some authentications here
        http.Redirect(w, r, "/", http.StatusFound)
    }
}

Then I redirect to another page "/info" from current page "/" (which has only buttons):

func manage(w http.ResponseWriter, r *http.Request) {
    t, err := template.ParseFiles("manage/manage.html")
    checkError(err)
    t.Execute(w, nil)
    r.ParseForm()
    if r.Form["Button"] != nil { //to get only POST actions from buttons
        if r.Form["Button"][0] == "Log" {
            http.Redirect(w, r, "/info", http.StatusFound)
        } 
    }
}

At last, I made a template and would like to show on client side:

const tpl=`stuff inside`

type InfoDefault struct {
    //stuff inside
}

func info(w http.ResponseWriter, r *http.Request) {
    info := InfoDefault{
        //stuff inside
    }

    t, err := template.New("info").Parse(tpl)
    checkError(err)
    err = t.Execute(os.Stdout, info)
    checkError(err)
}

Now, the weird thing is, when I click the button on page "/", I got the error "http: multiple response.WriteHeader calls". At the same time a link called "found" shows up on the bottom of my page (weird!), and when I click the link "found", I got all my parsed template printed on the server side instead of webpage.

Does anyone know why...? And how to fix the error and print stuff on client webpage? Thank you!!!

As JimB already pointed out: your server gets confused because there are different status codes associated with both writing to http.ResponseWriter and the redirect . You can't do both at the same time.

I would actually like to expand more on how you can carry data over to the next page (assuming you are redirecting).

Headers You can write some information to the request object and receive it on the destination page. Example:

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("My-Awesome-Header", "Rocks")
    ...
}

Session: You are talking about access control as far as I can see, and I think persisting user data is better done through a session. Example: you can use a database or a session handler like https://github.com/gorilla/sessions . Check out this thread: Best practice with sessions (gorilla/sessions) .

Cookies: I'm not sure what kind of front-end you are using, but storing non-sensitive data on the cookie could be an option? Nothing beats this one (it has real choc-chip cookies in the examples ;-) ): https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/06.1.html .

In your manage handler, you're executing the template which will write to the http.ResponseWriter and trigger an http.StatusOK (200) status code. You can't redirect after that, since that requires sending a different response code.

If you need to redirect, do it before executing the template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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