Home > Back-end >  How to proxy a preflight request with status OK using Go?
How to proxy a preflight request with status OK using Go?

Time:12-30

Given a client making a HTTP request

<!DOCTYPE html>
<html>
    <body>
        <script>
            fetch('http://localhost:3000/messages', {
                method: 'POST',
                headers: { 'content-type': 'application/json' },
                body: JSON.stringify({ data: 'foo' })
            })
            .then(async response => {
                console.log(await response.json());
            });
        </script>
    </body>
</html>

The API server does not handle the request, the request handler should act as a proxy and send the request to another server

import (
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/messages", handleRequest)

    http.ListenAndServe(":3000", mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "*")
    w.Header().Set("Access-Control-Allow-Methods", "*")

    targetUrl, _ := url.Parse("http://localhost:3001/messages")

    proxy := httputil.NewSingleHostReverseProxy(targetUrl)
    proxy.ServeHTTP(w, r)
}

The target server should handle the request and send back the response

import (
    "encoding/json"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/messages", handleRequest)

    http.ListenAndServe(":3001", mux)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "*")
    w.Header().Set("Access-Control-Allow-Methods", "*")

    w.WriteHeader(http.StatusOK)

    json.NewEncoder(w).Encode("bar")
}

I start both servers and run the .html file, I would expect a

bar

in the console. But unfortunately I get the error

Access to fetch at 'http://localhost:3000/messages' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

enter image description here

Does someone know how to fix this?

CodePudding user response:

You need to add a different path for handling preflight requests in your proxy. this is how your proxy should look like:

func handleRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "*")
    w.Header().Set("Access-Control-Allow-Methods", "*")

    if r.Method == "OPTIONS" {
        w.WriteHeader(http.StatusOK)
        return
    }
    targetUrl, _ := url.Parse("http://localhost:3001")

    proxy := httputil.NewSingleHostReverseProxy(targetUrl)
    proxy.ServeHTTP(w, r)
}

Notice the changes:

  1. OPTION requests(preflights) are not passed to server, you just accept them by sending a OK status.

  2. (irrelevant to CORS problem) target url should not have /message part. path part is already present in your request, you should not repeat it.

Also you need to change the server code and remove these headers:

// w.Header().Set("Access-Control-Allow-Origin", "*")
// w.Header().Set("Access-Control-Allow-Headers", "*")
// w.Header().Set("Access-Control-Allow-Methods", "*")

They are already set by the proxy. Server doesn't respond to the web-browser anymore.

  •  Tags:  
  • go
  • Related