Golang 简单 http 代理转发

程序基本实现了对http的完整转发,目前暂不支持https

windows需要在设置中的网络>代理设置为手动,并开启代理服务器,填写ip和端口

// httpForward
package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "strconv"
    "strings"
)

func HttpForward(pattern string, port int) {
    http.HandleFunc(pattern, doGo)
    strPort := strconv.Itoa(port)
    fmt.Print("listenning on :", " ", pattern, " ", strPort, "\n")
    err := http.ListenAndServe(":"+strPort, nil)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

func doGo(w http.ResponseWriter, r *http.Request) {

    //r.host不带http,r.url是完整的url
    //fmt.Println(r.Host, " ", r.URL, "\n")

    fmt.Println("url: ", r.URL)

    //查看url各个信息
    // str := "hi ,it is working"
    // b := []byte(str)
    //w.Write(b)
    //fmt.Print(r.Host, " ", r.Method, " \nr.URL.String ", r.URL.String(), " r.URL.Host ", r.URL.Host, " r.URL.Fragment ", r.URL.Fragment, " r.URL.Hostname ", r.URL.Hostname(), " r.URL.RequestURI ", r.URL.RequestURI(), " r.URL.Scheme ", r.URL.Scheme)

    cli := &http.Client{}

    //不建议用readfull,对于body大小难以判断,容易出错
    // body := make([]byte, 2048000)
    // n, err := io.ReadFull(r.Body, body)

    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        fmt.Print("io.ReadFull(r.Body, body) ", err.Error())
        //return,没有数据也是可以的,不需要直接结束
    }
    fmt.Print("req count :", len(body), "\n")

    //fmt.Print(len(body))
    //reqUrl := r.Host + r.URL.String()

    reqUrl := r.URL.String()

    //url里带了协议类型,不需要用scheme
    // if r.URL.Scheme != "" {
    //     reqUrl = r.URL.Scheme + reqUrl
    // } else {
    //     reqUrl = "http://" + reqUrl
    // }

    req, err := http.NewRequest(r.Method, reqUrl, strings.NewReader(string(body)))
    if err != nil {
        fmt.Print("http.NewRequest ", err.Error())
        return
    }

    //用遍历header实现完整复制
    //contentType := r.Header.Get("Content-Type")
    //req.Header.Set("Content-Type", contentType)

    for k, v := range r.Header {
        req.Header.Set(k, v[0])
    }
    res, err := cli.Do(req)
    if err != nil {
        fmt.Print("cli.Do(req) ", err.Error())
        return
    }
    defer res.Body.Close()

    // n, err = io.ReadFull(res.Body, body)
    // if err != nil {
    //     fmt.Print("io.ReadFull(res.Body, body) ", err.Error())
    //     return
    // }
    //fmt.Print("count body bytes: ", n, "\n")

    for k, v := range res.Header {
        w.Header().Set(k, v[0])
    }
    io.Copy(w, res.Body)

    //这样复制对大小控制较差,不建议。用copy即可
    // io.WriteString(w, string(body[:n]))
    // fmt.Print(string(body))
}

我发现使用https时,程序似乎接收不到请求,没有反应,不知道是不是证书的问题

posted @ 2019-06-18 17:16  波士地盘  阅读(4815)  评论(0编辑  收藏  举报