duanjie6912 2018-03-29 03:22
浏览 70
已采纳

如何通过golang制作代理

I'm trying to make a proxy by golang.

The origin version is written by lua, nginx like this:

location / {
    keepalive_timeout  3600s;
    keepalive_requests 30000;
    rewrite_by_lua_file ./test.lua;
    proxy_pass http://www.example.com/bd/news/home;
}

and lua file like this:

local req_params = ngx.req.get_uri_args()
local args = {
    media = 24,
    submedia = 46,
    os = req_params.os,
    osv = req_params.osv,
    make = req_params.make,
    model = req_params.model,
    devicetype = req_params.devicetype,
    conn = req_params.conn,
    carrier = req_params.carrier,
    sw = req_params.w,
    sh = req_params.h,
}
if tonumber(req_params.os) == 1 then
    args.imei = req_params.imei
    args.adid = req_params.android_id
end
ngx.req.set_uri_args(args)

I try to do the same thing by golang, and my code is like this:

const newsTargetURL = "http://www.example.com/bd/news/home"

func GetNews(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodGet {
        http.Error(w, "only get allowed", http.StatusMethodNotAllowed)
        return
    }

    // deal params
    rq := r.URL.Query()
    os := rq.Get("os")
    osv := rq.Get("osv")
    imei := rq.Get("imei")
    androidID := rq.Get("android_id")
    deviceMake := rq.Get("make")
    model := rq.Get("model")
    deviceType := rq.Get("devicetype")
    sw := rq.Get("w")
    sh := rq.Get("h")
    conn := rq.Get("conn")
    carrier := rq.Get("carrier")
    uv := make(url.Values)
    uv.Set("media", "24")
    uv.Set("submedia", "46")
    uv.Set("os", os)
    uv.Set("osv", osv)
    if os == "1" {
        uv.Set("imei", imei)
        uv.Set("anid", androidID)
    }
    uv.Set("make", deviceMake)
    uv.Set("model", model)
    uv.Set("sw", sw)
    uv.Set("sh", sh)
    uv.Set("devicetype", deviceType)
    uv.Set("ip", ip)
    uv.Set("ua", ua)
    uv.Set("conn", conn)
    uv.Set("carrier", carrier)
    t := newsTargetURL + "?" + uv.Encode()
    // make a director
    director := func(req *http.Request) {
        u, err := url.Parse(t)
        if err != nil {
            panic(err)
        }
        req.URL = u
    }

    // make a proxy
    proxy := &httputil.ReverseProxy{Director: director}
    proxy.ServeHTTP(w, r)
}

func main() {
    mux := http.NewServeMux()

    mux.Handle("/", http.HandlerFunc(GetNews))

    srv := &http.Server{
        Addr:    ":2222",
        Handler: mux,
    }
    srv.ListenAndServe()
}

I put this go version to the same server where lua version locate, but it does not work as lua file do. I read the httputil document but found nothing that can help. What do I need to do?

  • 写回答

1条回答 默认 最新

  • douhui9192 2018-03-29 18:19
    关注

    I wrote together a simple proxy for GET requests. Hope this helps.

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "log"
        "net/http"
    )
    
    const newsTargetURL = "http://www.example.com/bd/news/home"
    
    func main() {
        mux := http.NewServeMux()
    
        mux.Handle("/", http.HandlerFunc(GetNews))
    
        srv := &http.Server{
            Addr:    ":2222",
            Handler: mux,
        }
        // output error and quit if ListenAndServe fails
        log.Fatal(srv.ListenAndServe())
    }
    
    func GetNews(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodGet {
            http.Error(w, "only get allowed", http.StatusMethodNotAllowed)
            return
        }
    
        // build proxy url
        urlstr := fmt.Sprintf("%s?%s", newsTargetURL, r.URL.RawQuery)
    
        // request the proxy url
        resp, err := http.Get(urlstr)
        if err != nil {
            http.Error(w, fmt.Sprintf("error creating request to %s", urlstr), http.StatusInternalServerError)
            return
        }
        // make sure body gets closed when this function exits
        defer resp.Body.Close()
    
        // read entire response body
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            http.Error(w, "error reading response body", http.StatusInternalServerError)
            return
        }
    
        // write status code and body from proxy request into the answer
        w.WriteHeader(resp.StatusCode)
        w.Write(body)
    }
    

    You can try it as is. It will work and show the content of example.com.

    It uses a single handler GetNews for all requests. It skips all of the request parameter parsing and building by simply using r.url.RawQuery and newsTargetURL to build the new url.

    Then we make a request to the new url (the main part missing in your question). From the response we read resp.StatusCode and resp.body to use in our response to the original request.

    The rest is error handling.

    The sample does not forward any additional information like cookies, headers, etc. That can be added as needed.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了