V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
DollarKiller
V2EX  ›  问与答

Golang 实现多域名 HTTPS 反向代理的思考

  •  
  •   DollarKiller · 2022-08-29 13:39:04 +08:00 · 1192 次点击
    这是一个创建于 808 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我看现在关于 golang 反向代理的实现基本依靠的是 httputil.ReverseProxy :

    import (
        "log"
        "net/http"
        "net/http/httputil"
        "net/url"
    )
    
    // NewProxy takes target host and creates a reverse proxy
    // NewProxy 拿到 targetHost 后,创建一个反向代理
    func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
        url, err := url.Parse(targetHost)
        if err != nil {
            return nil, err
        }
    
        return httputil.NewSingleHostReverseProxy(url), nil
    }
    
    // ProxyRequestHandler handles the http request using proxy
    // ProxyRequestHandler 使用 proxy 处理请求
    func ProxyRequestHandler(proxy *httputil.ReverseProxy) func( http.ResponseWriter, *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            proxy.ServeHTTP(w, r)
        }
    }
    
    func main() {
        // initialize a reverse proxy and pass the actual backend server url here
        // 初始化反向代理并传入真正后端服务的地址
        proxy, err := NewProxy("http://my-api-server.com")
        if err != nil {
            panic(err)
        }
    
        // handle all requests to your server using the proxy
        // 使用 proxy 处理所有请求到你的服务
        http.HandleFunc("/", ProxyRequestHandler(proxy))
        log.Fatal( http.ListenAndServe(":8080", nil))
    }
    

    上面的代码只实现了 监听一个端口 来实现特点网站的反向代码

    怎么实现类似 nginx 监听一个端口 支持多个网站的反代实现呢 我想通过 r.URL.Host 针对不同来来源来进行不同的操作 实现了 HTTP 的 单端口多网站的代理实现

    return func(w http.ResponseWriter, r *http.Request) {
    		r.URL.Host
    		proxy.ServeHTTP(w, r)
    	}
    

    但是 HTTPS 的怎么做了, 每个不同的域名都有不同的证书

    log.Fatal( http.ListenAndServe(":8080", nil))
    	
    http.ListenAndServeTLS()
    
    3 条回复    2022-08-29 13:56:50 +08:00
    dzdh
        1
    dzdh  
       2022-08-29 13:48:33 +08:00
    前阵子刚研究过。

    伪代码:

    ```
    func main() {

    tlsConfig := &tls.Config{
    GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {

    return tls.X509KeyPair(certBlockByte, keyBlockByte), nil
    },
    }

    httpsSrv := http.Server{
    Addr: ":443",
    TLSConfig: tlsConfig,
    }
    httpSrv := http.Server{
    Addr: ":80",
    }
    go httpSrv.ListenAndServe()
    go httpsSrv.ListenAndServe()

    }
    ```
    dzdh
        2
    dzdh  
       2022-08-29 13:50:47 +08:00   ❤️ 1
    GetCertificate 部分通过接口也好,通过数据库、redis 都可,返回一个 tls.Certficiate 就可

    proxy.ServeHTTP 的 request,在传入前,把 request.Host 置空,否则不走 r.URL.Host 直接走了 r.Host
    DollarKiller
        3
    DollarKiller  
    OP
       2022-08-29 13:56:50 +08:00
    @dzdh 谢谢老师 太厉害了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5024 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 03:53 · PVG 11:53 · LAX 19:53 · JFK 22:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.