## 构建反向代理 本节我们将建立一个反向代理应用。我们的想法是,通过请求http:// localhost:3333,所有流量都将转发到可配置的主机,响应将转发到你的浏览器。 这可以与端口转发和ssh隧道结合使用,以便通过中间服务器安全地访问网站。本节将从头开始构建反向代理,但标准库的net/http/httputil包也提供此功能。使用此包,可以通过Director func(*http.Request)修改传入请求,并且可以通过 ModifyResponse func(*http.Response) error错误修改传出响应。 此外,还支持缓冲响应。 ### 实践 1. 建立 proxy.go: ``` package proxy import ( "log" "net/http" ) // Proxy 保存了客户端配置和需要代理的BaseURL地址 type Proxy struct { Client *http.Client BaseURL string } // ServeHTTP 表示代理部署了Handler接口它操纵请求,将其转发给BaseURL,然后返回响应 func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := p.ProcessRequest(r); err != nil { log.Printf("error occurred during process request: %s", err.Error()) w.WriteHeader(http.StatusBadRequest) return } resp, err := p.Client.Do(r) if err != nil { log.Printf("error occurred during client operation: %s", err.Error()) w.WriteHeader(http.StatusInternalServerError) return } defer resp.Body.Close() CopyResponse(w, resp) } ``` 2. 建立 process.go: ``` package proxy import ( "bytes" "net/http" "net/url" ) // ProcessRequest 根据Proxy设置修改请求 func (p *Proxy) ProcessRequest(r *http.Request) error { proxyURLRaw := p.BaseURL + r.URL.String() proxyURL, err := url.Parse(proxyURLRaw) if err != nil { return err } r.URL = proxyURL r.Host = proxyURL.Host r.RequestURI = "" return nil } // CopyResponse获取客户端响应并将所有内容写入原始处理程序中的ResponseWriter func CopyResponse(w http.ResponseWriter, resp *http.Response) { var out bytes.Buffer out.ReadFrom(resp.Body) for key, values := range resp.Header { for _, value := range values { w.Header().Add(key, value) } } w.WriteHeader(resp.StatusCode) w.Write(out.Bytes()) } ``` 3. 建立 main.go: ``` package main import ( "fmt" "net/http" "github.com/agtorre/go-cookbook/chapter7/proxy" ) func main() { p := &proxy.Proxy{ Client: http.DefaultClient, BaseURL: "https://www.golang.org", } http.Handle("/", p) fmt.Println("Listening on port :3333") err := http.ListenAndServe(":3333", nil) panic(err) } ``` 4. 这会输出: ``` $ go run main.go Listening on port :3333 ``` 在浏览器地址栏输入localhost:3333/,你会看到跳转到了https://golang.org/。 ### 说明 Go请求和响应对象在很大程度上可以在客户端和处理程序之间共享。示例代码接受由满足Handler接口的Proxy结构获取的请求。一旦请求可用,它就被修改为在请求之前添加Proxy.BaseURL。最后,响应被复制回ResponseWriter接口。 我们还可以添加一些其他功能,例如请求的基本身份验证,令牌管理等。这对于代理管理JavaScript或其他客户端应用程序的会话令牌管理非常有用。 * * * * 学识浅薄,错误在所难免。欢迎在群中就本书提出修改意见,以飨后来者,长风拜谢。 Golang中国(211938256) beego实战(258969317) Go实践(386056972)