golang 反向代理

服务器

package main

import (
    "bytes"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "math/rand"
    "net/http"

    "golang.org/x/net/websocket"
)

var cp = make(chan []byte)
var res = make(chan []byte, 1)

//var uri_chan_map = make(map[string]chan *Return_content)
var uri_chan_map = make(map[string]chan map[string]interface{})

type Req_Group struct {
    Method string
    Header http.Header
    Body   []byte
    Uri    string
    Host   string
    Id     string
}
type Return_content struct {
    Uri    string      `json:"uri"`
    Id     string      `json:"id"`
    Header http.Header `json:"header"`
    Body   []byte      `json:"body"`
}

func Soket(ws *websocket.Conn) {
    //设置连接超时, 如果websocket客户端连接后, 客户端响应时间超过设置的等待时间, 则websocket服务端主动断开连接
    //ws.SetReadDeadline(time.Now().Add(30 * time.Second))
    //ws.RemoteAddr()远程地址(客户端地址), ws.LocalAddr()本地地址(服务器地址)
    fmt.Printf("websocket %s->%s 通信连接已建立:\n", ws.RemoteAddr().String(), ws.LocalAddr().String())
    //标记出错, false表示没出错, true表示出错
    var err_message = false
    //外层for循环一次发送一次请求信息
    for true {
        data := <-cp
        ws.Write(data)
        //从缓存中一次只读取1024字节, 如果接收数据过多, 可以将读取内容存在一个可变的数组中,循环读取到缓存无数据即可
        //将每次读取的1024字节存放在msg中, 然后append到result_msg中
        msg := make([]byte, 1024)
        //将所有的读取信息存放在result_msg中
        var result_msg []byte
        //内层for循环用来读取response信息
        for true {
            n, err := ws.Read(msg)
            //这里的问题是websocket客户端的问题
            if err != nil {
                fmt.Println("websocket客户端出现错误或断开")
                res_msg := make(map[string]string)
                res_msg["err"] = err.Error()
                new_msg, _ := json.Marshal(res_msg)

                new_msg = []byte(new_msg)
                result_msg = append(result_msg, new_msg...)
                //出错就把标记表量设置为true
                err_message = true
                break
            }
            if n != 0 && string(msg[:n]) != "OVER" {
                //msg的元素被打散一个个append进result_msg, 如果不加... 直接写会报错
                new_msg := msg[:n]
                result_msg = append(result_msg, new_msg...)
                //fmt.Printf("读取了%d字节\n", n)
                msg = make([]byte, 1024)
            } else if string(msg[:n]) == "OVER" {
                fmt.Println("websocket传输完毕!")
                break
            }
        }
        //err_message为true就代表websocket客户端出错, 需要退出发送信息的外循环, 并断开websocket连接
        if err_message {
            //将出错信息返回给http客户端
            res <- result_msg
            //每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误
            msg = make([]byte, 1024)
            result_msg = []byte{}
            break
        }
        res <- result_msg
        //每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误
        msg = make([]byte, 1024)
        result_msg = []byte{}
    }
    ws.Close()
}

func Handler(w http.ResponseWriter, r *http.Request) {
    //处理请求
    fmt.Printf("http客户端: %s 请求uri: %s 已连接...\n", r.RemoteAddr, r.URL.Path)
    //允许访问所有的域
    w.Header().Set("Access-Control-Allow-Origin", "*")
    //reflect.TypeOf(r).String():  *http.Request
    var req Req_Group
    req.Method = string(r.Method)
    req.Header = r.Header
    //使用随机字符串作为标识
    req.Id = randomString(10)
    defer r.Body.Close()
    body, _ := ioutil.ReadAll(r.Body)
    req.Body = body
    req.Uri = r.URL.Path
    req.Host = "https://192.168.18.97"
    var uri_chan = make(chan map[string]interface{})
    json_req, _ := json.Marshal(req)
    //设置随机字符串Id对应的通道
    uri_chan_map[req.Id] = uri_chan
    cp <- json_req

    new_content := <-uri_chan_map[req.Id]
    send_message(new_content, w, r)
}

func send_message(new_content map[string]interface{}, w http.ResponseWriter, r *http.Request) {
    delete(new_content, "Id")

    if _, ok := new_content["header"]; ok {
        //返回response头信息
        for k, v := range new_content["header"].(map[string]interface{}) {
            switch tp := v.(type) {
            case []interface{}:
                for _, u := range tp {
                    w.Header().Set(k, u.(string))
                }
            case string:
                w.Header().Set(k, v.(string))
            }
        }
        对body进行base64解码
        decodeBytes, err := base64.StdEncoding.DecodeString(new_content["body"].(string))
        if err != nil {
            log.Fatalln(err)
        }
        w.Write(decodeBytes)
        fmt.Printf("http 客户端: %s: 响应uri: %s 请求的uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string), r.URL.Path)
        return
    } else {
        w.Write([]byte(new_content["err"].(string)))
        fmt.Printf("出现错误, http 客户端: %s: 请求uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string))
        return
    }

}

//生成随机数函数
func randomString(l int) string {
    var result bytes.Buffer
    var temp string
    for i := 0; i < l; {
        temp = string(randInt(65, 90))
        result.WriteString(temp)
        i++

    }
    return result.String()
}

func randInt(min int, max int) int {
    return min + rand.Intn(max-min)
}

func main() {
    go func() {
        for {
            content := <-res
            var new_content map[string]interface{}
            err := json.Unmarshal(content[:len(content)], &new_content)
            if err != nil {
                log.Fatal("err-->Handler json反解析 ", err)
            }
            uri_chan_map[new_content["id"].(string)] <- new_content
        }
    }()

    fmt.Println("服务器已开启, 等待客户端连接...")
    http.HandleFunc("/", Handler)
    http.Handle("/echo", websocket.Handler(Soket))
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("err -> main", err)
    }
}
反向代理客户端
package main

import (
    "bytes"
    "crypto/tls"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "net/http"

    "golang.org/x/net/websocket"
)

type Return_content struct {
    Uri    string      `json:"uri"`
    Id     string      `json:"id"`
    Header http.Header `json:"header"`
    Body   []byte      `json:"body"`
}

//客户端地址,自己设置, 但是端口要和服务器监听的端口一致
var origin = "http://127.0.0.1:8080/"

//服务器地址(在服务器设置端口/后的参数)
var url = "ws://127.0.0.1:8080/echo"

var ch = make(chan []byte)
var res_str = make(chan string)

func Forward(ws *websocket.Conn, receive_con map[string]interface{}) {
    for true {
        result := <-ch
        _, err := ws.Write(result)
        if err != nil {
            log.Fatal("err -> Forward: ", err)
        }

        var over = "OVER"
        _, err = ws.Write([]byte(over))
        fmt.Println("转发成功!")
        start()
    }
}

func http_DO(receive_con map[string]interface{}) {
    //go实现的Client端默认也是要对服务端传过来的数字证书进行校验的,访问https需要让client端略过对证书的校验:
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
    request_url := "https://192.168.18.97"
    if _, ok := receive_con["Uri"]; ok {
        request_url = request_url + receive_con["Uri"].(string)
    }
    //根据是否有请求体区分
    if len(receive_con["Body"].(string)) > 0 {
        decodeBytes, err := base64.StdEncoding.DecodeString(receive_con["Body"].(string))
        if err != nil {
            log.Fatalln(err)
        }
        send_message(client, receive_con, request_url, bytes.NewReader(decodeBytes))
    } else {
        form_data := bytes.NewReader(nil)
        send_message(client, receive_con, request_url, form_data)
    }
}

func send_message(client *http.Client, receive_con map[string]interface{}, request_url string, form_data io.Reader) {
    rep, err := http.NewRequest(receive_con["Method"].(string), request_url, form_data)
    //设置请求头
    rep.Header.Set("Host", receive_con["Host"].(string))
    for k1, v1 := range receive_con["Header"].(map[string]interface{}) {
        if k1 != "Accept-Encoding" && k1 != "Accept-Language" && k1 != "Id" {
            for _, v2 := range v1.([]interface{}) {
                rep.Header.Set(k1, v2.(string))
            }
        }
    }
    resp, err := client.Do(rep)
    fmt.Println("status: ", resp.StatusCode)
    if err != nil {
        fmt.Println("请求出错", err)
    }
    Return_response_message(receive_con["Uri"].(string), resp, receive_con["Id"].(string))
}

func Return_response_message(uri string, resp *http.Response, Id string) {
    fmt.Println("请求uri:  ", uri)
    defer resp.Body.Close()
    var return_content Return_content
    return_content.Id = Id
    return_content.Uri = uri
    return_content.Header = resp.Header
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    //将body进行base64编码之后和json.Marshal的body结果一样
    //encodeString := base64.StdEncoding.EncodeToString(body)
    //fmt.Println("encodeString: ", encodeString)
    return_content.Body = body
    json_return_content, _ := json.Marshal(return_content) // body是base64编码
    ch <- json_return_content
}

func start() {
    ws, err := websocket.Dial(url, "", origin)
    for true {
        if err != nil {
            log.Fatal("err1 -> start: ", err)
        }
        var msg = make([]byte, 2048)
        m, err := ws.Read(msg)
        if err != nil {
            log.Fatal("err2 -> start: ", err)
        }
        web_message := msg[:m]
        //解析websocket发送的message
        var jx_web_message map[string]interface{}
        err = json.Unmarshal(web_message, &jx_web_message)
        if err != nil {
            log.Fatal("err3 -> start: ", err)
        }
        defer func() {
            ws.Close()
        }()
        go Forward(ws, jx_web_message)
        http_DO(jx_web_message)
    }
}

func main() {
    start()
}


转载于:https://www.cnblogs.com/nyist-xsk/p/10641293.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值