goProxy 伺服器代碼

來源:互聯網
上載者:User

標籤:代理   伺服器   golang   

goProxy 伺服器代碼

最近用廢棄的小筆記本搭了個centos伺服器掛著,搭了ssh,tomcat,go環境,想搭個Proxy 伺服器訪問路由,不想安裝,想自己寫一個,順便複習一下go語言知識。

一開始,我網上搜了一下go語言寫Proxy 伺服器的代理,搜尋到一個:
來自:http://symphony.b3log.org/article/1357452978419
(原文地址:http://kejibo.com/golang-http-proxy-server 已失效)

package mainimport (    "http"    "log"    "os"    "io/ioutil")func handler(w http.ResponseWriter, r *http.Request) {    resp, err := http.DefaultClient.Do(r)    defer resp.Body.Close()    if err != nil { panic(err) }    for k, v := range resp.Header {        for _, vv := range v {            w.Header().Add(k, vv)        }    }    for _, c := range resp.SetCookie {        w.Header().Add("Set-Cookie", c.Raw)    }    w.WriteHeader(resp.StatusCode)    result, err := ioutil.ReadAll(resp.Body)    if err != nil && err != os.EOF { panic(err) }    w.Write(result)}func main() {    http.HandleFunc("/", handler)    log.Println("Start serving on port 8888")    http.ListenAndServe(":8888", nil)    os.Exit(0)}

寫成檔案上傳到伺服器,go build test.go 編譯,發現resp.SetCookie根本沒有這個方法,編譯不通過,上面文章說它要最新的http源碼並編譯到go源碼裡,我都驚呆了,還要修改它的源碼啊,我看了下自己的go語言版本,是1.4.2,是15年今年的了,他寫的文章的時候是13年,呵呵了,我的比他的新多了,怎麼可能會舊?!還有他說的編譯源碼,是多麼複雜啊~

於是乎。機智的我,為了編譯通過,活生生的把它注釋了。
go build test.go
好了,編譯通過,執行它
/.test
顯示開啟了,還是要證實一下,掃描一下連接埠,看了下確實開了。

好像完成了喔,於是去瀏覽器設定一下代理,開啟baidu.com,他告訴我方法錯誤了,我查看了一下列印資訊,發現
defer resp.Body.Close()
這行報這個錯:
invalid memory address or nil pointer dereference
網上找了一下,原來是resp變數null 指標錯誤。
我又嘗試列印err資訊:
http: Request.RequestURI can’t be set in client requests.

就是說,ttp.DefaultClient.Do(r)這個用法是不正確的,是不能這樣設定的,於是我找了一個替代品:http.NewRequest,它的優點就是可以get也可以post,應該還有put等操作,沒嘗試。

於是這段handler function被我耐心的改成了這樣:

func handler(w http.ResponseWriter, r *http.Request) {    fmt.Println("url:",r.RequestURI)    fmt.Println("method:",r.Method)    fmt.Println("header:",r.Header)    client0 := &http.Client{}    req, _ := http.NewRequest(r.Method, r.RequestURI, r.Body)    fmt.Printf("send:%+v\n", req)                                                         //看下發送的結構    resp, err := client0.Do(req) //發送    if err!=nil {                fmt.Println("error:",err)            }    defer resp.Body.Close()    for _, value := range resp.Request.Cookies() {        w.Header().Add(value.Name,value.Value)    }    for k, v := range resp.Header {                for _, vv := range v {                    w.Header().Add(k, vv)                }            }    w.WriteHeader(resp.StatusCode)    result, err := ioutil.ReadAll(resp.Body)    if (err != nil) {        fmt.Println("error:",err)    }    fmt.Println("result:" ,result);    _,err = w.Write(result)    if (err != nil) {        fmt.Println("error:",err)    }

實際上我是在mac電腦上編輯的,用伺服器上傳在編譯運行速度太慢了 = =、
看上去,代碼好像寫的很不錯的樣子。
運行起來,訪問baidu死迴圈啦,我又改了幾次,看了幾次,還是這樣,無奈的我只好測試其他網站,那個測試的網站是我的一個簡單的jsp網頁,就一個簡單的列表,我一訪問,竟然快速的出現了,竟然成功訪問了,可是我沒改到什麼代碼啊,我在認真的想了一想,應該是訪問baidu的時候沒有放要求標頭過去,導致它訪問baidu.com的時候,源碼裡面的連結是post訪問的,且都是baidu.com,為了證實我的猜想,我添加了要求標頭個cookie上去

......    req, _ := http.NewRequest(r.Method, r.RequestURI, r.Body)    for k, v := range req.Header {        for _, vv := range v {            r.Header.Add(k, vv)        }    }    for _, value := range req.Cookies() {        r.Header.Add(value.Name,value.Value)    }......

編譯運行,瀏覽器重新重新整理,竟然一下子就打了,我的猜想原來是正確的。
伺服器基本完成,進入測試階段,先百度一下,成功了,不過部分圖片裂開了,在進入其他的,csdn可以訪問,圖片問題,sina正常,oschina正常,就是百度那個圖片載入時裂了。讀者有興趣自行研究研究,在這,我只是先把簡單的Proxy 伺服器帖上來,方便大家使用。

最後瀏覽了一下整改Proxy 伺服器的代碼:

package mainimport (    "net/http"    "log"    "io/ioutil"//  "io"    "fmt")func handler(w http.ResponseWriter, r *http.Request) {//  http.DefaultClient.//  w.Write([]byte("dddd"))    fmt.Println("url:",r.RequestURI)    fmt.Println("method:",r.Method)    fmt.Println("header:",r.Header)    client0 := &http.Client{}    req, _ := http.NewRequest(r.Method, r.RequestURI, r.Body)    for k, v := range req.Header {        for _, vv := range v {            r.Header.Add(k, vv)        }    }    for _, value := range req.Cookies() {        r.Header.Add(value.Name,value.Value)    }    fmt.Printf("send:%+v\n", req)                                                         //看下發送的結構    resp, err := client0.Do(req) //發送    if err!=nil {                fmt.Println("error:",err)            }    defer resp.Body.Close()    for _, value := range resp.Request.Cookies() {        w.Header().Add(value.Name,value.Value)    }    for k, v := range resp.Header {                for _, vv := range v {                    w.Header().Add(k, vv)                }            }    w.WriteHeader(resp.StatusCode)    result, err := ioutil.ReadAll(resp.Body)    if (err != nil) {        fmt.Println("error:",err)    }    fmt.Println("result:" ,result);    _,err = w.Write(result)    if (err != nil) {        fmt.Println("error:",err)    }}func main() {    http.HandleFunc("/", handler)    log.Println("Start serving on port 8089")     http.ListenAndServe(":8089", nil)    log.Println("server start")}

看看自己改的代碼,和網上那個人得代碼,原來相差那麼多,看哭了。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

goProxy 伺服器代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.