(转) Golang 中的反向代理

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

反相代理可用于解决多个服务器,或者隐藏服务器。
例如之前考虑的穷人版分布式:我在全国部署了多台迷你服务器,通过中心服务器(反向代理)的中转,确定需要提供的服务器,让真正服务器与客户端连接。

package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strings"
)

const PORT = "1330"
const A_CONDITION_URL = "http://localhost:1331"
const B_CONDITION_URL = "http://localhost:1332"
const DEFAULT_CONDITION_URL = "http://localhost:1333"

type requestPayloadStruct struct {
    ProxyCondition string `json:"proxy_condition"`
}

// Get the port to listen on
func getListenAddress() string {
    return ":" + PORT
}

// Log the env variables required for a reverse proxy
func logSetup() {
    a_condtion_url := A_CONDITION_URL
    b_condtion_url := B_CONDITION_URL
    default_condtion_url := DEFAULT_CONDITION_URL

    log.Printf("Server will run on: %s\n", getListenAddress())
    log.Printf("Redirecting to A url: %s\n", a_condtion_url)
    log.Printf("Redirecting to B url: %s\n", b_condtion_url)
    log.Printf("Redirecting to Default url: %s\n", default_condtion_url)
}

// Get a json decoder for a given requests body
func requestBodyDecoder(request *http.Request) *json.Decoder {
    // Read body to buffer
    body, err := ioutil.ReadAll(request.Body)
    if err != nil {
        log.Printf("Error reading body: %v", err)
        panic(err)
    }

    // Because go lang is a pain in the ass if you read the body then any susequent calls
    // are unable to read the body again....
    request.Body = ioutil.NopCloser(bytes.NewBuffer(body))

    return json.NewDecoder(ioutil.NopCloser(bytes.NewBuffer(body)))
}

// Parse the requests body
func parseRequestBody(request *http.Request) requestPayloadStruct {
    decoder := requestBodyDecoder(request)

    var requestPayload requestPayloadStruct
    err := decoder.Decode(&requestPayload)

    if err != nil {
        panic(err)
    }

    return requestPayload
}

// Log the typeform payload and redirect url
func logRequestPayload(requestionPayload requestPayloadStruct, proxyUrl string) {
    log.Printf("proxy_condition: %s, proxy_url: %s\n", requestionPayload.ProxyCondition, proxyUrl)
}

// Get the url for a given proxy condition
func getProxyUrl(proxyConditionRaw string) string {
    proxyCondition := strings.ToUpper(proxyConditionRaw)

    a_condtion_url := A_CONDITION_URL
    b_condtion_url := B_CONDITION_URL
    default_condtion_url := DEFAULT_CONDITION_URL

    if proxyCondition == "A" {
        return a_condtion_url
    }

    if proxyCondition == "B" {
        return b_condtion_url
    }

    return default_condtion_url
}

// Serve a reverse proxy for a given url
func serveReverseProxy(target string, res http.ResponseWriter, req *http.Request) {
    // parse the url
    url, _ := url.Parse(target)

    // create the reverse proxy
    proxy := httputil.NewSingleHostReverseProxy(url)

    // Update the headers to allow for SSL redirection
    //req.URL.Host = url.Host
    //req.URL.Scheme = url.Scheme
    //req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
    //req.Host = url.Host

    // Note that ServeHttp is non blocking and uses a go routine under the hood
    proxy.ServeHTTP(res, req)
}

// Given a request send it to the appropriate url
func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
    requestPayload := parseRequestBody(req)
    url := getProxyUrl(requestPayload.ProxyCondition)

    logRequestPayload(requestPayload, url)

    serveReverseProxy(url, res, req)
}

func main() {
    // Log setup values
    logSetup()

    // start server
    http.HandleFunc("/", handleRequestAndRedirect)
    if err := http.ListenAndServe(getListenAddress(), nil); err != nil {
        panic(err)
    }
}

相关文章