Why HTTP response status is hidden in net/http?

5,218 views
Skip to first unread message

Robert Zaremba

unread,
Apr 29, 2013, 11:06:49 PM4/29/13
to golan...@googlegroups.com
Is there any reason for hiding status in ``response.status`` (in package "net/http")?

Why don't we have a function to get it out, eg: ``rw.Status()`` (like we have with Headers)?

It would be very helpful to get access to this field for example when creating some handlers pipeline (middleware).

minux

unread,
Apr 29, 2013, 11:38:21 PM4/29/13
to Robert Zaremba, golan...@googlegroups.com
On Tue, Apr 30, 2013 at 11:06 AM, Robert Zaremba <robert....@zoho.com> wrote:
Is there any reason for hiding status in ``response.status`` (in package "net/http")?
are you talking about the unexported struct "response"?
that struct itself is unexported, so are its fields.

Why don't we have a function to get it out, eg: ``rw.Status()`` (like we have with Headers)?

It would be very helpful to get access to this field for example when creating some handlers pipeline (middleware).
perhaps you should take a look at the Response struct, which does export Status and StatusCode. 

Robert Zaremba

unread,
Apr 30, 2013, 4:31:15 AM4/30/13
to golan...@googlegroups.com, Robert Zaremba
Actually I'm talking about http.ResponseWriter interface.
So there is no way to get status code in  http.Handler. It Might be useful when Handlers are chained

Rémy Oudompheng

unread,
Apr 30, 2013, 4:54:57 AM4/30/13
to Robert Zaremba, golang-nuts
2013/4/30 Robert Zaremba <robert....@zoho.com>:
> Actually I'm talking about http.ResponseWriter interface.
> So there is no way to get status code in http.Handler. It Might be useful
> when Handlers are chained

The status code is produced by your application, so you are supposed
to already know it: you should not consider the ResponseWriter as a
storage system, because doing so implies more restrictions the
interface.

What does it mean that handlers are chained?

You can define your own type:

type RichHandler func(w http.ResponseWriter, req *http.Request) (int, error)

and make it implement the http.Handler interface if needed.

Rémy.

Jackie Li

unread,
Apr 30, 2013, 5:19:50 AM4/30/13
to Robert Zaremba, golang-nuts
You mean something like this:

type WrapHTTPHandler struct {
m http.Handler
}

func (h *WrapHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
lw := &loggedResponse{ResponseWriter: w}
h.m.ServeHTTP(lw, r)
log.SetPrefix("[Info]")
log.Printf("[%s] %s - %d\n", r.RemoteAddr, r.URL, lw.status)
}

type loggedResponse struct {
http.ResponseWriter
status int
}

func (l *loggedResponse) WriteHeader(status int) {
l.status = status
l.ResponseWriter.WriteHeader(status)
}

func main(){
    http.ListenAndServe(*addr, &WrapHTTPHandler{router})
}



--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Jackie

Jackie Li

unread,
Apr 30, 2013, 5:37:08 AM4/30/13
to Robert Zaremba, golang-nuts
Some Notes:
1. The "router" can be DefaultServeMux 
2. if Status is not explicitly set in you Handler, it'll be set to 200: StatusOK. It's documented here: http://golang.org/pkg/net/http/#ResponseWriter, so it might be better to do this:

func (h *WrapHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
lw := &loggedResponse{ResponseWriter: w, status:200}
h.m.ServeHTTP(lw, r)
log.SetPrefix("[Info]")
log.Printf("[%s] %s - %d\n", r.RemoteAddr, r.URL, lw.status)
}

Any suggestion from anyone?


Thanks,
Jackie
--
Jackie

Robert Zaremba

unread,
Apr 30, 2013, 6:08:10 AM4/30/13
to golan...@googlegroups.com, Robert Zaremba
Handler interface is standardised and already there are of 3rd party handlers to work with it (like authorization check).
We can wrap or chain this handlers, like:

    type Pipeline struct {
        curr http.Handler
        next http.Handler
    }
    func (this Pipeline) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        curr(w,r)
        next(w,r)
    }

    func main(){
        ...
        p := Pipeline{LogHandler, IndexHandler}
        http.ListenAndServe(*addr, p)
    }


@Jackie - if you want your code to work then you need to wrap every handler with WrapHTTPHandler, not only the router.

@Rémy Oudompheng - I agree that we ResponseWriter shouldn't be a storage.



Having Status() method (analogous to Header()) would be much clean solution

Martin Angers

unread,
Apr 30, 2013, 8:58:07 AM4/30/13
to golan...@googlegroups.com, Robert Zaremba
Like Jackie mentioned, it is fairly easy to created what I call an "augmented" response writer and intercept the calls to get the status code. Should it or should it not be included natively in ResponseWriter is another debate, but you can still build pretty much all features you want on top of the simple ServeHTTP method signature, thanks to the extensible nature of the ResponseWriter (thanks to it being an interface, that is). That's the approach I've used in my collection of middleware handlers in ghost (https://github.com/PuerkitoBio/ghost).

Robert Zaremba

unread,
Apr 30, 2013, 10:30:31 AM4/30/13
to golan...@googlegroups.com, Robert Zaremba
Thank you for your comments!

Jackie Li

unread,
Apr 30, 2013, 11:30:10 AM4/30/13
to Robert Zaremba, golang-nuts
@Jackie - if you want your code to work then you need to wrap every handler with WrapHTTPHandler, not only the router.

Hmmm, I don't understand what you mean.

Can you have a look at this?


Cheers,




--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Jackie
Reply all
Reply to author
Forward
0 new messages