• 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 通信连接已建立:
    ", 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)
    				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 已连接...
    ", 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 已完成
    ", r.RemoteAddr, new_content["uri"].(string), r.URL.Path)
    		return
    	} else {
    		w.Write([]byte(new_content["err"].(string)))
    		fmt.Printf("出现错误, http 客户端: %s: 请求uri: %s 已完成
    ", 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()
    }
    
    
    
    
  • 相关阅读:
    如何较为方便的在GMap.Net中实现车辆运行轨迹
    WPF中在摄像头视频上叠加控件的解决方案
    Image Perimeters
    [DFS]排队(间隔排列)-C++
    稀疏图判定
    兔子问题(Rabbit problem)
    YCOJ过河卒C++
    洛谷P1076 寻宝
    P1993 小K的农场(差分约束)
    大Jump!
  • 原文地址:https://www.cnblogs.com/nyist-xsk/p/10641293.html
Copyright © 2020-2023  润新知