服務器
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()
}