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.

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

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?