使用 Go to Cloud Run 实例的反向代理

我觉得我已经接近完成这项工作,但到目前为止,我遇到了一个问题,在 Go 中构建一个小型反向代理到 GCP Cloud Run 实例。请求“通过”,但请求的响应是默认的GCP Cloud Run 404。将请求返回到 Cloud Run 时会出现主机标头被忽略,因此请求没有被路由更正。


我可能在这里缺少什么?


package main


import (

    "log"

    "net/http"

    "net/http/httputil"

    "net/url"

)


const apiUrl = "MY_CLOUD_RUN.a.run.app"


func main() {

    http.HandleFunc("/", proxy)

    log.Fatal(http.ListenAndServe(":8081", nil))

}


func proxy(res http.ResponseWriter, req *http.Request) {

    // gets past CORS checks

    if req.Method == http.MethodOptions {

        headers := res.Header()

        headers.Add("Access-Control-Allow-Origin", "*")

        headers.Add("Vary", "Origin")

        headers.Add("Vary", "Access-Control-Request-Method")

        headers.Add("Vary", "Access-Control-Request-Headers")

        headers.Add("Access-Control-Allow-Headers", "*")

        headers.Add("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE")

        res.WriteHeader(http.StatusOK)

        return

    }


    p := httputil.NewSingleHostReverseProxy(&url.URL{

        Scheme: "http",

        Host:   apiUrl,

    })

    p.Director = func(req *http.Request) {

        req.Header.Add("X-Forwarded-Host", req.Host)

        req.Header.Add("X-Origin-Host", apiUrl)

        req.Header.Add("Host", apiUrl)

        req.Header.Add("Access-Control-Allow-Origin", "*")

        req.URL.Scheme = "https"

        req.URL.Host = apiUrl

    }

    p.ModifyResponse = func(res *http.Response) error {

        res.Header.Set("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE")

        res.Header.Set("Access-Control-Allow-Credentials", "true")

        res.Header.Set("Access-Control-Allow-Origin", "*")

        res.Header.Set("Access-Control-Allow-Headers", "*")

        return nil

    }


    p.ServeHTTP(res, req)

}


慕仙森
浏览 71回答 1
1回答

莫回无

这比最初的最初写的要复杂一些,但我们最终得到的结果如下。package mainimport (&nbsp; &nbsp; "context"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "net/http/httputil"&nbsp; &nbsp; "net/url"&nbsp; &nbsp; "os"&nbsp; &nbsp; "os/signal"&nbsp; &nbsp; "time"&nbsp; &nbsp; "golang.org/x/oauth2"&nbsp; &nbsp; "google.golang.org/api/idtoken")var port = ":8080"var backend = "[CLOUD_RUN_INSTANCE_TO_PROXY].a.run.app"func main() {&nbsp; &nbsp; logger := log.New(os.Stdout, "proxy: ", log.LstdFlags)&nbsp; &nbsp; logger.Println(fmt.Sprintf("Proxy server is starting for: %s on port: %s", backend, port))&nbsp; &nbsp; router := http.NewServeMux()&nbsp; &nbsp; router.Handle("/", proxyHandler())&nbsp; &nbsp; server := &http.Server{&nbsp; &nbsp; &nbsp; &nbsp; Addr:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;port,&nbsp; &nbsp; &nbsp; &nbsp; Handler:&nbsp; &nbsp; &nbsp; logging(logger)(router),&nbsp; &nbsp; &nbsp; &nbsp; ErrorLog:&nbsp; &nbsp; &nbsp;logger,&nbsp; &nbsp; &nbsp; &nbsp; ReadTimeout:&nbsp; 30 * time.Second,&nbsp; &nbsp; &nbsp; &nbsp; WriteTimeout: 30 * time.Second,&nbsp; &nbsp; &nbsp; &nbsp; IdleTimeout:&nbsp; 15 * time.Second,&nbsp; &nbsp; }&nbsp; &nbsp; done := make(chan bool)&nbsp; &nbsp; quit := make(chan os.Signal, 1)&nbsp; &nbsp; signal.Notify(quit, os.Interrupt)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; <-quit&nbsp; &nbsp; &nbsp; &nbsp; logger.Println("Proxy server is shutting down...")&nbsp; &nbsp; &nbsp; &nbsp; ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)&nbsp; &nbsp; &nbsp; &nbsp; defer cancel()&nbsp; &nbsp; &nbsp; &nbsp; server.SetKeepAlivesEnabled(false)&nbsp; &nbsp; &nbsp; &nbsp; if err := server.Shutdown(ctx); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; close(done)&nbsp; &nbsp; }()&nbsp; &nbsp; if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {&nbsp; &nbsp; &nbsp; &nbsp; logger.Fatalf("Could not listen on %s: %v\n", port, err)&nbsp; &nbsp; }&nbsp; &nbsp; <-done&nbsp; &nbsp; logger.Println("Server stopped")}func proxyHandler() http.Handler {&nbsp; &nbsp; return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; if r.Method == http.MethodOptions {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headers := w.Header()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headers.Add("Access-Control-Allow-Origin", "*")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headers.Add("Access-Control-Allow-Headers", "*")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headers.Add("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(http.StatusOK)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; path := fmt.Sprintf("https://%s%s", backend, r.RequestURI)&nbsp; &nbsp; &nbsp; &nbsp; at, _ := idTokenTokenSource(path)&nbsp; &nbsp; &nbsp; &nbsp; p := httputil.NewSingleHostReverseProxy(&url.URL{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Scheme: "https",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Host:&nbsp; &nbsp;backend,&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; p.Director = func(r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if at != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; at.SetAuthHeader(r)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; p.ModifyResponse = func(res *http.Response) error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.Header.Set("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.Header.Set("Access-Control-Allow-Credentials", "true")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.Header.Set("Access-Control-Allow-Origin", "*")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.Header.Set("Access-Control-Allow-Headers", "*")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; r.URL.Scheme = "https"&nbsp; &nbsp; &nbsp; &nbsp; r.URL.Host = backend&nbsp; &nbsp; &nbsp; &nbsp; r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))&nbsp; &nbsp; &nbsp; &nbsp; r.Host = backend&nbsp; &nbsp; &nbsp; &nbsp; if at != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; at.SetAuthHeader(r)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; p.ServeHTTP(w, r)&nbsp; &nbsp; })}func logging(l *log.Logger) func(http.Handler) http.Handler {&nbsp; &nbsp; return func(next http.Handler) http.Handler {&nbsp; &nbsp; &nbsp; &nbsp; return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; requestId := r.Header.Get("X-Request-Id")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if requestId == "" {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; requestId = fmt.Sprintf("%d", time.Now().UnixNano())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.Header().Set("X-Request-Id", requestId)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l.Println(requestId, r.Method, r.URL.Path, r.RemoteAddr, r.UserAgent())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; next.ServeHTTP(w, r)&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }}func idTokenTokenSource(audience string) (*oauth2.Token, error) {&nbsp; &nbsp; ts, err := idtoken.NewTokenSource(context.Background(), audience)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return nil, err&nbsp; &nbsp; }&nbsp; &nbsp; t, err := ts.Token()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return nil, err&nbsp; &nbsp; }&nbsp; &nbsp; return t, nil}一些正常关闭、http 设置和日志记录的很大一部分来自:https ://gist.github.com/enricofoltran/10b4a980cd07cb02836f70a4ab3e72d7
打开App,查看更多内容
随时随地看视频慕课网APP