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)
}
说明:因篇幅原因,以上代码省略了必要的错误和异常处理,只起到示范说明作用。
评论
