go代理服务器代码

u010499721 · · 7858 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

go代理服务器代码

最近用废弃的小笔记本搭了个centos服务器挂着,搭了ssh,tomcat,go环境,想搭个代理服务器访问路由,不想安装,想自己写一个,顺便复习一下go语言知识。

一开始,我网上搜了一下go语言写代理服务器的代理,搜索到一个:
来自:http://symphony.b3log.org/article/1357452978419
(原文地址:http://kejibo.com/golang-http-proxy-server 已失效)

package main

import (
    "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变量空指针错误。
我又尝试打印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网页,就一个简单的列表,我一访问,竟然快速的出现了,竟然成功访问了,为什么百度的不行呢?我又试了试淘宝的网站,也是很快出现了,可是我没改到什么代码啊,就在我百事不得其解的时候,脑子闪出一个想法:可能是百度首页有复杂的判断导致代理服务器的请求死循环了,为了证实我的想法,我在浏览器输入网址:
http://www.baidu.com/s?wd=key
竟然能访问了!至于为什么会这样,读者有兴趣自行研究研究,在这,我只是先把简单的代理服务器帖上来,方便大家使用。

最后浏览了一下整改代理服务器的代码:


package main

import (
"net/http"
"log"
"io/ioutil"
"fmt"
)


func handler(w http.ResponseWriter, r *http.Request) {
    req, _ := http.NewRequest(r.Method, r.RequestURI, r.Body)
    for k, v := range r.Header {
        for _, vv := range v {
            req.Header.Add(k, vv)
        }
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")

    client := &http.Client{}
    resp, err := client.Do(req)

    if err!=nil {
        fmt.Println("error:",err)
    }

    defer resp.Body.Close()


    for k, v := range resp.Header {
        for _, vv := range v {
            w.Header().Add(k, vv)
        }
    }

    for _, value := range resp.Request.Cookies() {
        w.Header().Add(value.Name,value.Value)
    }

    w.WriteHeader(resp.StatusCode)

    result, err := ioutil.ReadAll(resp.Body)
    if (err != nil) {
        fmt.Println("error:",err)
    }

    _,err = w.Write(result)
    if (err != nil) {
        fmt.Println("error:",err)
    }
}

func main() {
    http.HandleFunc("/", handler)
    log.Println("Start serving on port 8089")
    err := http.ListenAndServe(":8089", nil)
    if (err!=nil) {
        log.Println("error:",err)
    }
}

看看自己改的代码,和网上那个人得代码,原来相差那么多,看哭了。

版权声明:本文为博主原创文章,未经博主允许不得转载。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:u010499721

查看原文:go代理服务器代码

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

7858 次点击  
加入收藏 微博
1 回复  |  直到 2000-01-01 00:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传