There's not a nice way to serialize the http.Request structure itself (see notes below), but you can serialize the request back into HTTP/1.1 wire format (and deserialize too). This can be done using Request.Write and http.ReadRequest:
func captureRequestData(req *http.Request) error {
var b = &bytes.Buffer{} // holds serialized representation
var tmp *http.Request
var err error
if err = req.Write(b); err != nil { // serialize request to HTTP/1.1 wire format
return err
}
r := bufio.NewReader(b)
if tmp, err = http.ReadRequest(r); err != nil { // deserialize request
return err
}
*req = *tmp // replace original request structure
return nil
}
Persistence of the serialized buffer is just a matter of saving a copy of b. You might prefer to persist the string representation, which involves some additional conversions:
s := b.String() // persist this
r := bufio.NewReader(strings.NewReader(s))
There are a couple of reasons, at least, why you can't just use json.Marshal() for this:
The public fields of Request include functions, which Marshall does not accept:
json: unsupported type: func() (io.ReadCloser, error)
Request also contains a private field ctx which thwarts any generic attempts at deserialization:
ctx is either the client or server context. It should only
be modified via copying the whole Request using WithContext.
It is unexported to prevent people from using Context wrong
and mutating the contexts held by callers of the same request.