2

Here is the schema :

Client sends a POST request to server A

server A process this and sends a GET to server B

server B sends a response through A to the client


I though the best idea was to make a pipe which would read the response of the GET, and write into the response of the POST, but I got many types problems.

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/test/{hash}", testHandler)

    log.Fatal(http.ListenAndServe(":9095", r))
}

func handleErr(err error) {
    if err != nil {
        log.Fatalf("%s\n", err)
    }
}


func testHandler(w http.ResponseWriter, r *http.Request){

    fmt.Println("FIRST REQUEST RECEIVED")
    vars := mux.Vars(r)
    hash := vars["hash"]
    read, write := io.Pipe()

    // writing without a reader will deadlock so write in a goroutine
    go func() {
        write, _ = http.Get("http://localhost:9090/test/" + hash)
        defer write.Close()
    }()

    w.Write(read)
}

When I run this I get the following error:

./ReverseProxy.go:61: cannot use read (type *io.PipeReader) as type []byte in argument to w.Write

Is there a way, to properly insert a io.PipeReader format into an http response? Or am I doing this in a totally wrong way?

1
  • 1
    I think you're misunderstanding the purpose of an io.Pipe. Why not just copy the data from the response.Body to the ReponseWriter? (also, an http.Response doesn't have a Close method, you're shadowing the PipeWriter with the http.Response, and you need to check the error first) Commented Nov 22, 2016 at 16:50

1 Answer 1

9

You are not actually writing to it, you're replacing the pipe's write.

Something along the lines of:

func testHandler(w http.ResponseWriter, r *http.Request) {

    fmt.Println("FIRST REQUEST RECEIVED")

    vars := mux.Vars(r)
    hash := vars["hash"]

    read, write := io.Pipe()

    // writing without a reader will deadlock so write in a goroutine
    go func() {
        defer write.Close()
        resp, err := http.Get("http://localhost:9090/test/" + hash)
        if err != nil {
            return
        }
        defer resp.Body.Close()
        io.Copy(write, resp.Body)

    }()

    io.Copy(w, read)

}

Although, I agree with @JimB, for this instance, the pipe isn't even needed, something like this should be more efficient:

func testHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    hash := vars["hash"]

    resp, err := http.Get("http://localhost:9090/test/" + hash)
    if err != nil {
        // handle error
        return
    }
    defer resp.Body.Close()

    io.Copy(w, resp.Body)
}
Sign up to request clarification or add additional context in comments.

2 Comments

though there's no point in this io.Pipe fiasco, this is just an io.Copy with more copies.
@JimB I agree but I figured he might be trying to learn how to use it, I'll add another snip without it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.