Moduel ProxyHTTP 反向代理中間件
Module Proxy是一款HTTP反向代理中間件,突出的靚點(diǎn)是將HTTP協(xié)議代理為TCP Socket協(xié)議,特別適合Web前后臺(tái)分離的編程架構(gòu)項(xiàng)目,使用Module Proxy可以讓后端編程從HTTP技術(shù)體系中抽身出來(lái),這將帶來(lái)兩個(gè)重要的改變:
- 無(wú)Web編程經(jīng)驗(yàn)的程序員,可以輕松進(jìn)行B/S后端的編程工作 。
- 幾乎所有的現(xiàn)代編程語(yǔ)言,都可以被使用進(jìn)行B/S后端的編程工作,使用中不需要這些編程語(yǔ)言有HTTP的實(shí)現(xiàn)。
Module Proxy中間件由Rust語(yǔ)言實(shí)現(xiàn),使用了優(yōu)秀的異步運(yùn)行時(shí)Tokio和HTTP底層庫(kù)hyper,具有高效、穩(wěn)定、簡(jiǎn)單的特性。
Demo 程序示例
Ajax客戶端:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script> <script type="text/javascript"> $(function(){ // method是和后端服務(wù)的約定,這里表示調(diào)用后端的hello方法,data是前后端約定的業(yè)務(wù)數(shù)據(jù) var req_json = { "head":{"method":"hello"}, "data":{"hello":"world!!!", "list":[1,2,3,4]} }; $("#btn").click(function(){ $.ajax({ type: "POST", //傳輸方式POST url: "/socket1/", //提交URL, socket1是模塊名 contentType : "application/json; charset=utf-8", //Socket轉(zhuǎn)發(fā)的固定格式 data: JSON.stringify(req_json), success: function(rsp_json){ $("#myDiv").html('<h3>'+JSON.stringify(rsp_json)+'</h3>'); } }); }); }); </script> </head> <body> <button id="btn" type="button">submit</button> <div id="myDiv"></div> </body> </html>
Go語(yǔ)言實(shí)現(xiàn)的Socket端:
package main import ( "encoding/json" "fmt" "net" "strconv" "strings" "time" ) func main() { listener, err := net.Listen("tcp", "0.0.0.0:21231") //偵聽(tīng)端口21231 if err != nil { fmt.Println("listen error:", err) return } fmt.Println("server start...") for { conn, err := listener.Accept() if err != nil { fmt.Println("accept error:", err) break } go process(conn) //協(xié)程 } } func process(conn net.Conn) { defer conn.Close() //讀取req json長(zhǎng)度,長(zhǎng)度行是Module Proxy轉(zhuǎn)發(fā)時(shí)在Json數(shù)據(jù)前補(bǔ)充的 buf := make([]byte, 12) //長(zhǎng)度行總是12字節(jié) n, _ := conn.Read(buf) lenStr := string(buf[:n]) lenStr = strings.Trim(lenStr, "\r\n") //去除行尾的回車換行 lenStr = strings.Trim(lenStr, " ") //去除行左的空格 len, _ := strconv.Atoi(lenStr) //string轉(zhuǎn)int //讀取req json jsonBuf := make([]byte, len) n, _ = conn.Read(jsonBuf) //解析req json m := make(map[string]interface{}) //map json.Unmarshal(jsonBuf, &m) //json轉(zhuǎn)map method := m["head"].(map[string]interface{})["method"] data := m["data"] fmt.Println("method: ", method) fmt.Println("data: ", data) //調(diào)用業(yè)務(wù)函數(shù) var rspJson []byte var rsplen int switch method { case "hello": rspJson, rsplen = hello(data.(map[string]interface{})) //只傳入Json中的data數(shù)據(jù)部分 default: rspJson, rsplen = foo() } //返回 rsp json lenRsp := fmt.Sprintf("%10d\r\n", rsplen) //構(gòu)建12字節(jié)長(zhǎng)度行(左補(bǔ)空格,右補(bǔ)\r\n) conn.Write([]byte(lenRsp)) //socket返回 長(zhǎng)度行 conn.Write(rspJson) //socket返回 rsp json } func hello(m map[string]interface{}) ([]byte, int) { m["time"] = time.Now().Format("2006-01-02 15:04:05") m["module"] = "golang" b, _ := json.Marshal(m) //map轉(zhuǎn)json return b, len(b) } func foo() ([]byte, int) { b := []byte("{}") return b, len(b) }
說(shuō)明:因篇幅原因,以上代碼省略了必要的錯(cuò)誤和異常處理,只起到示范說(shuō)明作用。
評(píng)論
圖片
表情
