threading.Serve
在策略进程内创建Http服务、TCP服务、Websocket服务(基于Http协议),返回Server对象。
Serve(serveURI, handler)
Serve(serveURI, handler, ...args)示例
-
启动一个Http服务,并从主线程请求它。
javascriptfunction main() { var server = threading.Serve("http://127.0.0.1:8088", function (ctx) { ctx.write("hello " + ctx.path()) }) Log("serve on", server.addr()) // 输出:serve on 127.0.0.1:8088 Log(HttpQuery("http://127.0.0.1:8088/ping")) // 输出:hello /ping server.close() } -
在一个进程内启动Http(含WebSocket)和TCP回显服务,并逐一测试。
javascriptfunction main() { let httpServer = threading.Serve("http://:8088?gzip=true", function (ctx) { Log("http connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) let path = ctx.path() if (path == "/") { ctx.write(JSON.stringify({ path: ctx.path(), method: ctx.method(), headers: ctx.headers(), cookie: ctx.header("Cookie"), remote: ctx.remoteAddr(), query: ctx.rawQuery() })) } else if (path == "/tickers") { let ret = exchange.GetTickers() if (!ret) { ctx.setStatus(500) ctx.write(GetLastError()) } else { ctx.write(JSON.stringify(ret)) } } else if (path == "/wss") { if (ctx.upgrade("websocket")) { // upgrade to websocket while (true) { let r = ctx.read(10) if (r == "") { break } else if (r) { if (r == "ticker") { ctx.write(JSON.stringify(exchange.GetTicker())) } else { ctx.write("not support") } } } Log("websocket closed", ctx.remoteAddr()) } } else { ctx.setStatus(404) } }) let echoServer = threading.Serve("tcp://:8089", function (ctx) { Log("tcp connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) while (true) { let d = ctx.read() if (!d) { break } ctx.write(d) } Log("connect closed") }) Log("http serve on", httpServer.addr(), "tcp serve on", echoServer.addr()) for (var i = 0; i < 5; i++) { if (i == 2) { // test Http var retHttp = HttpQuery("http://127.0.0.1:8088?num=123&limit=100", {"debug": true}) Log("retHttp:", retHttp) } else if (i == 3) { // test TCP var tcpConn = Dial("tcp://127.0.0.1:8089") tcpConn.write("Hello TCP Server") var retTCP = tcpConn.read() Log("retTCP:", retTCP) } else if (i == 4) { // test Websocket var wsConn = Dial("ws://127.0.0.1:8088/wss|compress=gzip") wsConn.write("ticker") var retWS = wsConn.read(1000) Log("retWS:", retWS) // no depth wsConn.write("depth") retWS = wsConn.read(1000) Log("retWS:", retWS) } Sleep(1000) } httpServer.close() echoServer.close() }
返回值
| 类型 | 描述 |
| 返回 |
参数
| 名称 | 类型 | 必填 | 描述 |
serveURI | string | 是 | 服务的协议、绑定地址、端口和可选设置,例如 |
handler | function | 是 | 路由处理函数(Http协议)、消息处理函数(TCP协议)、Stream处理函数(Websocket)。每个TCP连接、每个Http请求都在独立的线程中调用一次该函数。 |
arg | string / number / bool / object / array / function / any | 否 | 传给回调函数 |
参考
备注
- 该函数仅支持JavaScript语言策略。
- 处理函数与
Thread创建的线程一样运行在隔离环境中,不能引用外部变量、闭包或自定义函数,需要的数据通过...args传入;可以调用平台所有的API函数。ThreadDict、ThreadLock等对象也可以作为参数传入,与其它线程共享数据。 - Http服务每个连接只处理一个请求,处理函数中
ctx.write()写入的内容在函数返回后一次性发送。 - 每个服务同时执行的处理函数最多64个,超出时Http请求返回
503,TCP连接直接断开。 - 策略停止时服务自动关闭;需要提前关闭时调用返回对象的
close()或stop()。 Websocket服务基于Http协议实现,可以在path中设置一个路由分支,设计Websocket消息订阅/推送的实现代码,可以参考本节范例代码。- 旧的全局函数
__Serve()仍然可以使用,参数相同,返回值是监听地址字符串,相当于threading.Serve(...).addr();新代码请使用threading.Serve()。
参数handler传入的回调处理函数接收一个ctx参数。ctx参数为一个上下文对象,用于获取数据和写入数据,有以下方法:
- ctx.proto()
应用于Http/TCP协议,调用时返回协议名称。例如:HTTP/1.1、tcp。 - ctx.host()
应用于Http协议,调用时返回主机信息:IP地址、端口。 - ctx.path()
应用于Http协议,调用时返回请求路径。 - ctx.query(key)
应用于Http协议,调用时返回请求中query查询中key对应的值。例如发送的请求为:http://127.0.0.1:8088?num=123,参数handler传入的回调处理函数中ctx.query("num")调用时返回"123"。 - ctx.rawQuery()
应用于Http协议,调用时返回请求中的原始查询(Http请求的query)。 - ctx.headers()
应用于Http协议,调用时返回请求中的请求头信息。 - ctx.header(key)
应用于Http协议,调用时返回指定的请求头中的某个key对应的值。例如获取当前请求的headers中的User-Agent:ctx.header("User-Agent")。 - ctx.method()
应用于Http协议,调用时返回请求方法,例如GET、POST等。 - ctx.body()
应用于Http协议的POST请求,调用时返回请求的正文。 - ctx.setHeader(key, value)
应用于Http协议,设置应答报文的请求头信息。 - ctx.setStatus(code)
应用于Http协议,设置Http报文状态码,通常在路由分支最后设置Http状态码,默认为200。 - ctx.remoteAddr()
应用于Http/TCP协议,调用时返回请求中的远程客户端地址、端口。 - ctx.localAddr()
应用于Http/TCP协议,调用时返回服务本地地址、端口。 - ctx.upgrade("websocket")
应用于基于Http协议的Websocket协议实现,切换ctx上下文对象为Websocket协议;切换成功返回布尔值(真),失败返回布尔值(假)。 - ctx.read(timeout_ms)
应用于基于Http协议的Websocket协议实现/TCP协议,读取Websocket连接的数据,TCP连接的数据,普通Http协议中不支持使用该read方法;可以指定超时时间参数timeout_ms,单位毫秒。超时返回null,对方关闭连接返回空字符串""。 - ctx.write(s)
应用于Http/TCP协议,用于写入字符串数据,可以使用JSON.stringify()编码JSON对象为字符串之后写入。对于WebSocket协议,可以使用该方法将编码后的字符串传递给客户端。
serveURI参数的写法:
- 协议前缀只支持
tcp://(TCP服务)和http://(HTTP服务)。WebSocket服务也用http://,在处理函数中调用ctx.upgrade("websocket")切换。 - IP可以省略,写成
http://:8088表示监听所有网卡;端口写0时随机分配空闲端口,实际地址用返回对象的addr()获取。 ?后面可以加gzip=true(启用gzip压缩)、tls=true(启用TLS加密:Https、wss、TLS加密的TCP)。启用TLS时必须同时用cert_pem和cert_key_pem传入PEM格式的证书和私钥(内容需要URL编码),例如http://:8443?tls=true&cert_pem=xxxx&cert_key_pem=xxxx;Https服务写成http://加tls=true。
arg参数的用法:下面调用Serve()时传入的1、2、3依次成为回调函数的参数a、b、c。
javascript
threading.Serve("http://:8088", function(ctx, a, b, c) {
Log(`ctx.host():`, ctx.host(), ", a=", a, ", b=", b, ", c=", c)
}, 1, 2, 3)