解码失败时获取原始XML

(go newbie here) I have some code like this:

func (c *clientImpl) queryHost(qtype string, page int) (io.ReadCloser, error) {
    queryURI := c.URL + "/api/query"
    req, _ := http.NewRequest(http.MethodGet, queryURI, nil)
    req.Header.Add(authHeaderName, authToken)
    req.Header.Add("Accept", accept)

    q := req.URL.Query()
    q.Add("type", qtype)
    q.Add("pageSize", pageSize)
    q.Add("page", strconv.Itoa(page))
    req.URL.RawQuery = q.Encode()
    resp, err := c.client.Do(req) //*http.Client
    if err != nil {
        return nil, utils.NestedError("Error in querying Host", err)
    }

    return resp.Body, nil
}

And then called like this:

body, err := c.queryHost(myQType, i)
        if err != nil {
            log.Printf("Error while trying to get page %v - %v 
", i, err)
            return err
        }
        defer body.Close()

        var qResult myQueryResult
        err = xml.NewDecoder(body).Decode(&myQueryResult)
        if err != nil {
            log.Printf("Error while decoding page %v - %v 
", i, err)
            return utils.NestedError("Error in decoding response body xml", err)
        }

I want to log the original xml that was failed to be processed, but since this is a ReadCloser and once read, it cannot be read again (or am I wrong?). Is there a way I can get this, or do I have to store the initial response somewhere and pass copies around?

  1. Read bytes with io/ioutil ReadAll

    defer body.Close()

    data, err := ioutil.ReadAll(body)

  2. Then unmarshal

    err = xml.Unmarshal(data, &qResult)

You can log data for checking original xml.

For http responses you can use the httputil package's DumpResponse:

Example from the link:

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
    "net/http/httputil"
)

func main() {
    const body = "Go is a general-purpose language designed with systems programming in mind."
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Date", "Wed, 19 Jul 1972 19:00:00 GMT")
        fmt.Fprintln(w, body)
    }))
    defer ts.Close()

    resp, err := http.Get(ts.URL)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    dump, err := httputil.DumpResponse(resp, true)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%q", dump)

}