Reuse for requests other than Get

package main

import (
 "net/http"
 "strings"
 )

func main(){
     reader := strings.NewReader("hello")
     req,_ := http.NewRequest("POST","http://www.abc.com",reader)
     client := http.Client{}
     client.Do(req) // First request will succeed
     client.Do(req) // Request fails
}

The second request will return an error

http: ContentLength=5 with Body length 0

The reason is that after the first request, req.Body has been read to the end, so the second request cannot read the body again. Solution: Redefine a implementation class of ReadCloser to replace req.Body

package reader

import (
 "io"
 "net/http"
 "strings"
 "sync/atomic"
)

type Repeat struct{
 reader io.ReaderAt
 offset int64
}

// Read Rewrite the read method so that each time request.Body is read, it can be read from the specified position
func (p *Repeat) Read(val []byte) (n int, err error) {
 n, err = p.reader.ReadAt(val, p.offset)
 atomic.AddInt64(&p.offset, int64(n))
 return
}

// Reset Reset offset
func (p *Repeat) Reset(){
        atomic.StoreInt64(&p.offset,0)
}

func (p *Repeat) Close() error {
    // Because req.Body implements the readcloser interface, the close method must be implemented
    // But the value in repeat may be read-only, so here just try to close it.
 if p.reader != nil {
      if rc, ok := p.reader.(io.Closer); ok {
       return rc.Close()
      }
     }
 return nil
}

func doPost()  {
    client := http.Client{}
    reader := strings.NewReader("hello")
    req , _ := http.NewRequest("POST","http://www.abc.com",reader)
    req.Body = &Repeat{reader:reader,offset:0}
    client.Do(req)
    // Reset offset to 0
    req.Body.(*Repeat).Reset()
    client.Do(req)
}

This way no error will be reported. Because the Close() method is also rewritten, it also solves the problem of req.Body automatically closing when the request is reused.