看分享,阅见世界,分享此刻。是一个整理、分享,搜索的网站。智阅无界,洞见未来。
  • 聚好看
  • 文章
  • 专题
  • 文章
  • 登录
  • 注册
网中看 网中看 1个月前

Go 简单而强大的反向代理(Reverse Proxy)

go

在本文中,我们将了解反向代理,它的应用场景以及如何在 Golang 中实现它。

反向代理是位于 Web 服务器前面并将客户端(例如 Web 浏览器)的请求转发到 Web 服务器的服务器。 它们让你可以控制来自客户端的请求和来自服务器的响应,然后我们可以利用这个特点, 可以增加缓存、做一些提高网站的安全性措施等。

在我们深入了解有关反向代理之前,让我们快速看普通代理(也称为正向代理)和反向代理之间的区别。

在正向代理中,代理代表原始客户端从另一个网站检索数据。 它位于客户端(浏览器)前面,并确保没有后端服务器直接与客户端通信。 所有客户端的请求都通过代理被转发,因此服务器只与这个代理通信(服务器会认为代理是它的客户端)。 在这种情况下,代理可以隐藏真正的客户端。
forward-proxy

另一方面,反向代理位于后端服务器的前面,确保没有客户端直接与服务器通信。 所有客户端请求都会通过反向代理发送到服务器,因此客户端始终只与反向代理通信, 而从不会直接与实际服务器通信。 在这种情况下,代理可以隐藏后端服务器。 几个常见的反向代理有 Nginx, HAProxy。
reverse-proxy

反向代理使用场景

负载均衡(Load balancing): 反向代理可以提供负载均衡解决方案,将传入的流量均匀地分布在不同的服务器之间,以防止单个服务器过载。

防止安全攻击: 由于真正的后端服务器永远不需要暴露公共 IP,所以 DDoS 等攻击只能针对反向代理进行, 这能确保在网络攻击中尽量多的保护你的资源,真正的后端服务器始终是安全的。

缓存: 假设你的实际服务器与用户所在的地区距离比较远,那么你可以在当地部署反向代理,它可以缓存网站内容并为当地用户提供服务。

SSL 加密: 由于与每个客户端的 SSL 通信会耗费大量的计算资源,因此可以使用反向代理处理所有与 SSL 相关的内容, 然后释放你真正服务器上的宝贵资源。

Golang 实现

  1. import (
  2. "log"
  3. "net/http"
  4. "net/http/httputil"
  5. "net/url"
  6. )
  7. // NewProxy takes target host and creates a reverse proxy
  8. // NewProxy 拿到 targetHost 后,创建一个反向代理
  9. func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
  10. url, err := url.Parse(targetHost)
  11. if err != nil {
  12. return nil, err
  13. }
  14. return httputil.NewSingleHostReverseProxy(url), nil
  15. }
  16. // ProxyRequestHandler handles the http request using proxy
  17. // ProxyRequestHandler 使用 proxy 处理请求
  18. func ProxyRequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
  19. return func(w http.ResponseWriter, r *http.Request) {
  20. proxy.ServeHTTP(w, r)
  21. }
  22. }
  23. func main() {
  24. // initialize a reverse proxy and pass the actual backend server url here
  25. // 初始化反向代理并传入真正后端服务的地址
  26. proxy, err := NewProxy("http://my-api-server.com")
  27. if err != nil {
  28. panic(err)
  29. }
  30. // handle all requests to your server using the proxy
  31. // 使用 proxy 处理所有请求到你的服务
  32. http.HandleFunc("/", ProxyRequestHandler(proxy))
  33. log.Fatal(http.ListenAndServe(":8080", nil))
  34. }

是的没错!这就是在 Go 中创建一个简单的反向代理所需的全部内容。 我们使用标准库 net/http/httputil 创建了一个单主机的反向代理。 到达我们代理服务器的任何请求都会被代理到位于 http://my-api-server.com。 如果你对 Go 比较熟悉,这个代码的实现一目了然。
修改响应

HttpUtil 反向代理为我们提供了一种非常简单的机制来修改我们从服务器获得的响应, 可以根据你的应用场景来缓存或更改此响应,让我们看看应该如何实现:

  1. // NewProxy takes target host and creates a reverse proxy
  2. func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
  3. url, err := url.Parse(targetHost)
  4. if err != nil {
  5. return nil, err
  6. }
  7. proxy := httputil.NewSingleHostReverseProxy(url)
  8. proxy.ModifyResponse = modifyResponse()
  9. return proxy, nil
  10. }
  11. func modifyResponse() func(*http.Response) error {
  12. return func(resp *http.Response) error {
  13. resp.Header.Set("X-Proxy", "Magical")
  14. return nil
  15. }
  16. }

可以在 modifyResponse 方法中看到 ,我们设置了自定义 Header 头。 同样,你也可以读取响应体正文,并对其进行更改或缓存,然后将其设置回客户端。

在 modifyResponse 中,可以返回一个错误(如果你在处理响应发生了错误), 如果你设置了 proxy.ErrorHandler, modifyResponse 返回错误时会自动调用 ErrorHandler 进行错误处理。

  1. // NewProxy takes target host and creates a reverse proxy
  2. func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
  3. url, err := url.Parse(targetHost)
  4. if err != nil {
  5. return nil, err
  6. }
  7. proxy := httputil.NewSingleHostReverseProxy(url)
  8. proxy.ModifyResponse = modifyResponse()
  9. proxy.ErrorHandler = errorHandler()
  10. return proxy, nil
  11. }
  12. func errorHandler() func(http.ResponseWriter, *http.Request, error) {
  13. return func(w http.ResponseWriter, req *http.Request, err error) {
  14. fmt.Printf("Got error while modifying response: %v \n", err)
  15. return
  16. }
  17. }
  18. func modifyResponse() func(*http.Response) error {
  19. return func(resp *http.Response) error {
  20. return errors.New("response body is invalid")
  21. }
  22. }

完整代码

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "net/http/httputil"
  8. "net/url"
  9. )
  10. // NewProxy takes target host and creates a reverse proxy
  11. func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
  12. url, err := url.Parse(targetHost)
  13. if err != nil {
  14. return nil, err
  15. }
  16. proxy := httputil.NewSingleHostReverseProxy(url)
  17. originalDirector := proxy.Director
  18. proxy.Director = func(req *http.Request) {
  19. originalDirector(req)
  20. modifyRequest(req)
  21. }
  22. proxy.ModifyResponse = modifyResponse()
  23. proxy.ErrorHandler = errorHandler()
  24. return proxy, nil
  25. }
  26. func modifyRequest(req *http.Request) {
  27. req.Header.Set("X-Proxy", "Simple-Reverse-Proxy")
  28. }
  29. func errorHandler() func(http.ResponseWriter, *http.Request, error) {
  30. return func(w http.ResponseWriter, req *http.Request, err error) {
  31. fmt.Printf("Got error while modifying response: %v \n", err)
  32. return
  33. }
  34. }
  35. func modifyResponse() func(*http.Response) error {
  36. return func(resp *http.Response) error {
  37. return errors.New("response body is invalid")
  38. }
  39. }
  40. // ProxyRequestHandler handles the http request using proxy
  41. func ProxyRequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
  42. return func(w http.ResponseWriter, r *http.Request) {
  43. proxy.ServeHTTP(w, r)
  44. }
  45. }
  46. func main() {
  47. // initialize a reverse proxy and pass the actual backend server url here
  48. proxy, err := NewProxy("http://my-api-server.com")
  49. if err != nil {
  50. panic(err)
  51. }
  52. // handle all requests to your server using the proxy
  53. http.HandleFunc("/", ProxyRequestHandler(proxy))
  54. log.Fatal(http.ListenAndServe(":8080", nil))
  55. }

反向代理非常强大,如文章之前所说,它有很多应用场景。你可以根据你的情况对其进行自定义。 如果遇到任何问题,我非常乐意为你提供帮助。 如果你觉得这篇文章有趣,请分享一下,让更多 gopher 可以阅读! 非常感谢你的阅读。

via: https://blog.joshsoftware.com/2021/05/25/simple-and-powerful-reverseproxy-in-go/

作者:Anuj Verma 译者:h1z3y3
https://h1z3y3.me/posts/simple-and-powerful-reverse-proxy-in-golang/



欢迎访问源界面 从代码出发,向无限可能延伸.
【 可以发现更多的个人博客站点,点点滴滴,网络空间中的站点生活! 】

生活看更多

  • © 2025 看分享 阅见世界,分享此刻。
  • 建议
  • | 鄂ICP备14016484号-7

    鄂公网安备 42068402000189

    访问微博看分享