Moduel ProxyHTTP 反向代理中间件
Module Proxy是一款HTTP反向代理中间件,突出的靓点是将HTTP协议代理为TCP Socket协议,特别适合Web前后台分离的编程架构项目,使用Module Proxy可以让后端编程从HTTP技术体系中抽身出来,这将带来两个重要的改变:
- 无Web编程经验的程序员,可以轻松进行B/S后端的编程工作 。
- 几乎所有的现代编程语言,都可以被使用进行B/S后端的编程工作,使用中不需要这些编程语言有HTTP的实现。
Module Proxy中间件由Rust语言实现,使用了优秀的异步运行时Tokio和HTTP底层库hyper,具有高效、稳定、简单的特性。
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是和后端服务的约定,这里表示调用后端的hello方法,data是前后端约定的业务数据 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转发的固定格式 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语言实现的Socket端:
package main import ( "encoding/json" "fmt" "net" "strconv" "strings" "time" ) func main() { listener, err := net.Listen("tcp", "0.0.0.0:21231") //侦听端口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) //协程 } } func process(conn net.Conn) { defer conn.Close() //读取req json长度,长度行是Module Proxy转发时在Json数据前补充的 buf := make([]byte, 12) //长度行总是12字节 n, _ := conn.Read(buf) lenStr := string(buf[:n]) lenStr = strings.Trim(lenStr, "\r\n") //去除行尾的回车换行 lenStr = strings.Trim(lenStr, " ") //去除行左的空格 len, _ := strconv.Atoi(lenStr) //string转int //读取req json jsonBuf := make([]byte, len) n, _ = conn.Read(jsonBuf) //解析req json m := make(map[string]interface{}) //map json.Unmarshal(jsonBuf, &m) //json转map method := m["head"].(map[string]interface{})["method"] data := m["data"] fmt.Println("method: ", method) fmt.Println("data: ", data) //调用业务函数 var rspJson []byte var rsplen int switch method { case "hello": rspJson, rsplen = hello(data.(map[string]interface{})) //只传入Json中的data数据部分 default: rspJson, rsplen = foo() } //返回 rsp json lenRsp := fmt.Sprintf("%10d\r\n", rsplen) //构建12字节长度行(左补空格,右补\r\n) conn.Write([]byte(lenRsp)) //socket返回 长度行 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转json return b, len(b) } func foo() ([]byte, int) { b := []byte("{}") return b, len(b) }
说明:因篇幅原因,以上代码省略了必要的错误和异常处理,只起到示范说明作用。
评论