博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang 反向代理
阅读量:4965 次
发布时间:2019-06-12

本文共 9330 字,大约阅读时间需要 31 分钟。

服务器

package mainimport (    "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 mainimport (    "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

你可能感兴趣的文章
Ubuntu下安装Android Studio全过程(2015.01.27)
查看>>
ABAP术语-Company Code
查看>>
学习笔记:弧度和角度转换的定义以及转换方法
查看>>
shell中的数值运算
查看>>
23种设计模式之六(工厂模式)
查看>>
HashSet、TreeSet和LinkedHashSet分别基于HashMap、TreeMap和LinkedHashMap
查看>>
maven 添加json-lib包 or自定义jar包
查看>>
linux之ssh服务
查看>>
Xcode工程各个文件夹作用及新建工程参数含意
查看>>
while用法
查看>>
码流识别与传输
查看>>
关于H5页面在微信浏览器中视频播放的问题
查看>>
01.Python基础-1.Python简介及基础
查看>>
自定义注解
查看>>
poj 2299 归并排序求逆序数 (可做模板)
查看>>
图论浅析--最小生成树之Prim
查看>>
ora-01031:insufficient privileges解决方法 - 转
查看>>
log4j详解(二)
查看>>
滚动条
查看>>
数据结构之---C语言实现图的邻接表存储表示
查看>>