標籤:代理 伺服器 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 伺服器代碼