M8Test Help

HTTP 服务器

您可以在脚本中启动一个本地 HTTP 服务器,用于接收外部请求,这在模拟 API、搭建临时 Web 服务等场景中非常有用。

启动和停止服务器

import com.m8test.script.GlobalVariables.* // 确保脚本在后台运行 _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) val port = 8080 // 启动一个服务器 val httpServer = _httpServers.startServer(port) { routing { // get 的处理器是 HttpServerCall.(CoroutineScope) -> Job // 所以 lambda 只有一个参数 s (CoroutineScope),HttpServerCall 是 this get("/") { s -> val request = getRequest() // 使用 this.getRequest() _console.log("[服务器] 收到来自 ${request.getOriginConnectionPoint().getRemoteHost()} 的根路径请求") // respondText 返回一个 Job getResponse().respondText(s, "你好,世界!来自 M8Test HTTP 服务器.") { it.getTextPlain() } } get("/json") { s -> _console.log("[服务器] 收到 /json 路径请求") val jsonResponse = """{"status": "ok", "timestamp": ${System.currentTimeMillis()}}""" getResponse().respondText(s, jsonResponse) { it.getApplicationJson() } } } } _console.log("HTTP 服务器已在 http://127.0.0.1:$port 启动") // 创建客户端进行测试 val httpClient = _httpClients.newClient(null) // 延迟1秒确保服务器已完全启动 scope.delay(1000).then { s, v -> _console.log("[客户端] 开始测试服务器...") val req1 = httpClient.get(s, "http://127.0.0.1:$port/", null, null) val req2 = httpClient.get(s, "http://127.0.0.1:$port/json", null, null) // 等待所有请求完成 s.awaitAll(listOf(req1, req2)) }.then { s, responses -> val resp1Text = responses[0].getTextBody(s) val resp2Text = responses[1].getTextBody(s) s.awaitAll(listOf(resp1Text, resp2Text)) }.then { s, bodies -> _console.log("[客户端] 根路径响应:", bodies[0]) _console.log("[客户端] /json 路径响应:", bodies[1]) s.resolve(null) }.onError { error -> _console.error("[客户端] 测试失败:", error) }.onComplete { _console.log("测试完成,正在关闭服务器...") _httpServers.stopServer(httpServer) }
// 确保脚本在后台运行 $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) def port = 8080 // 启动一个服务器 def httpServer = $httpServers.startServer(port, { config -> config.routing({ route -> route.get("/", { call, s -> def request = call.getRequest() $console.log("[服务器] 收到来自 ${request.getOriginConnectionPoint().getRemoteHost()} 的根路径请求") // respondText 现在返回一个 Job,这成为 get 处理器块的返回值 call.getResponse().respondText(s, "你好,世界!来自 M8Test HTTP 服务器。", { it.getTextPlain() }) }) route.get("/json", { call, s -> $console.log("[服务器] 收到 /json 路径请求") def jsonResponse = '{"status": "ok", "timestamp": ' + System.currentTimeMillis() + '}' call.getResponse().respondText(s, jsonResponse, { it.getApplicationJson() }) }) }) }) $console.log("HTTP 服务器已在 http://127.0.0.1:${port} 启动") // 创建客户端进行测试 def httpClient = $httpClients.newClient(null) // 延迟1秒确保服务器已完全启动 scope.delay(1000).then({ s, v -> $console.log("[客户端] 开始测试服务器...") def req1 = httpClient.get(s, "http://127.0.0.1:${port}/", null, null) def req2 = httpClient.get(s, "http://127.0.0.1:${port}/json", null, null) // 等待所有请求完成 s.awaitAll([req1, req2]) }).then({ s, responses -> def resp1Text = responses[0].getTextBody(s) def resp2Text = responses[1].getTextBody(s) s.awaitAll([resp1Text, resp2Text]) }).then({ s, bodies -> $console.log("[客户端] 根路径响应:", bodies[0]) $console.log("[客户端] /json 路径响应:", bodies[1]) s.resolve(null) }).onError({ error -> $console.error("[客户端] 测试失败:", error) }).onComplete({ $console.log("测试完成,正在关闭服务器...") $httpServers.stopServer(httpServer) })
// 确保脚本在后台运行 $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); const port = 8080; // 启动一个服务器 const httpServer = $httpServers.startServer(port, config => { config.routing(route => { route.get("/", (call, s) => { const request = call.getRequest(); $console.log("[服务器] 收到来自 " + request.getOriginConnectionPoint().getRemoteHost() + " 的根路径请求"); // respondText 现在返回一个 Job,这成为 get 处理器块的返回值,必须返回 return call.getResponse().respondText(s, "你好,世界!来自 M8Test HTTP 服务器。", it => it.getTextPlain()); }); route.get("/json", (call, s) => { $console.log("[服务器] 收到 /json 路径请求"); const jsonResponse = '{"status": "ok", "timestamp": ' + Date.now() + '}'; return call.getResponse().respondText(s, jsonResponse, it => it.getApplicationJson()); }); }); }); $console.log("HTTP 服务器已在 http://127.0.0.1:" + port + " 启动"); // 创建客户端进行测试 const httpClient = $httpClients.newClient(null); // 延迟1秒确保服务器已完全启动 scope.delay(1000).then((s, v) => { $console.log("[客户端] 开始测试服务器..."); const req1 = httpClient.get(s, "http://127.0.0.1:" + port + "/", null, null); const req2 = httpClient.get(s, "http://127.0.0.1:" + port + "/json", null, null); // 等待所有请求完成 return s.awaitAll([req1, req2]); }).then((s, responses) => { const resp1Text = responses[0].getTextBody(s); const resp2Text = responses[1].getTextBody(s); return s.awaitAll([resp1Text, resp2Text]); }).then((s, bodies) => { $console.log("[客户端] 根路径响应:", bodies[0]); $console.log("[客户端] /json 路径响应:", bodies[1]); return s.resolve(null); }).onError(error => { $console.error("[客户端] 测试失败:", error); }).onComplete(() => { $console.log("测试完成,正在关闭服务器..."); $httpServers.stopServer(httpServer); });
-- 确保脚本在后台运行 _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) local port = 8080 -- 引入 System 类用于获取时间戳 local System = require("m8test_java.java.lang.System") -- 启动一个服务器 local httpServer = _httpServers:startServer(port, function(config) config:routing(function(route) route:get("/", function(call, s) local request = call:getRequest() _console:log("[服务器] 收到来自 " .. request:getOriginConnectionPoint():getRemoteHost() .. " 的根路径请求") -- respondText 现在返回一个 Job,这成为 get 处理器块的返回值 return call:getResponse():respondText(s, "你好,世界!来自 M8Test HTTP 服务器。", function(it) return it:getTextPlain() end) end) route:get("/json", function(call, s) _console:log("[服务器] 收到 /json 路径请求") local jsonResponse = '{"status": "ok", "timestamp": ' .. tostring(System:currentTimeMillis()) .. '}' return call:getResponse():respondText(s, jsonResponse, function(it) return it:getApplicationJson() end) end) end) end) _console:log("HTTP 服务器已在 http://127.0.0.1:" .. tostring(port) .. " 启动") -- 创建客户端进行测试 local httpClient = _httpClients:newClient(nil) -- 延迟1秒确保服务器已完全启动 scope:delay(1000):_then(function(s, v) _console:log("[客户端] 开始测试服务器...") local req1 = httpClient:get(s, "http://127.0.0.1:" .. tostring(port) .. "/", nil, nil) local req2 = httpClient:get(s, "http://127.0.0.1:" .. tostring(port) .. "/json", nil, nil) -- 等待所有请求完成 return s:awaitAll(_iterables:listOf(req1, req2)) end):_then(function(s, responses) -- 修正:Java List 是 0-based 索引。第一个元素是 get(0),第二个是 get(1)。 local resp1Text = responses:get(0):getTextBody(s) local resp2Text = responses:get(1):getTextBody(s) -- 同样,这里也需要一个 Java List return s:awaitAll(_iterables:listOf(resp1Text, resp2Text)) end):_then(function(s, bodies) -- 修正:Java List 是 0-based 索引。 _console:log("[客户端] 根路径响应:", bodies:get(0)) _console:log("[客户端] /json 路径响应:", bodies:get(1)) return s:resolve(nil) end):onError(function(error) if error ~= nil then _console:error("[客户端] 测试失败:", error:stackTraceToString()) else _console:error("[客户端] 测试失败,但未提供错误详情。") end end):onComplete(function() _console:log("测试完成,正在关闭服务器...") _httpServers:stopServer(httpServer) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpServers $httpServers */ global $httpServers; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpClients $httpClients */ global $httpClients; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /** @var m8test_java\com\m8test\script\core\api\collections\Iterables $iterables */ global $iterables; /** @var m8test_java\java\lang\System $System */ use m8test_java\java\lang\System; // 确保脚本在后台运行 $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $port = 8080; // 启动一个服务器 $httpServer = $httpServers->startServer($port, function ($config) { $config->routing(function ($route) { $route->get(javaString("/"), function ($call, $s) { global $console; $request = $call->getRequest(); $console->log(javaString("[服务器] 收到来自 ") . $request->getOriginConnectionPoint()->getRemoteHost() . javaString(" 的根路径请求")); // respondText 现在返回一个 Job,这成为 get 处理器块的返回值 return $call->getResponse()->respondText($s, javaString("你好,世界!来自 M8Test HTTP 服务器。"), function ($it) { return $it->getTextPlain(); }); }); $route->get(javaString("/json"), function ($call, $s) { global $console; $console->log(javaString("[服务器] 收到 /json 路径请求")); $jsonResponse = javaString('{"status": "ok", "timestamp": ') . System::currentTimeMillis() . '}'; return $call->getResponse()->respondText($s, $jsonResponse, function ($it) { return $it->getApplicationJson(); }); }); }); }); $console->log(javaString("HTTP 服务器已在 http://127.0.0.1:${port} 启动")); // 创建客户端进行测试 $httpClient = $httpClients->newClient(null); // 延迟1秒确保服务器已完全启动 $scope->delay(1000)->then(function ($s, $v) use ($httpClient, $port) { global $console, $iterables; $console->log(javaString("[客户端] 开始测试服务器...")); $req1 = $httpClient->get($s, javaString("http://127.0.0.1:${port}/"), null, null); $req2 = $httpClient->get($s, javaString("http://127.0.0.1:${port}/json"), null, null); // 等待所有请求完成 (修正点1: 添加 return, 修正点2: 使用 listOf) return $s->awaitAll($iterables->listOf($req1, $req2)); })->then(function ($s, $responses) { global $iterables; $resp1Text = $responses->get(0)->getTextBody($s); $resp2Text = $responses->get(1)->getTextBody($s); // 修正点3: 同样使用 listOf 以保持一致和稳健 return $s->awaitAll($iterables->listOf($resp1Text, $resp2Text)); })->then(function ($s, $bodies) { global $console; $console->log(javaString("[客户端] 根路径响应:"), $bodies->get(0)); $console->log(javaString("[客户端] /json 路径响应:"), $bodies->get(1)); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("[客户端] 测试失败:"), $error); })->onComplete(function () use ($httpServer) { global $console, $httpServers; $console->log(javaString("测试完成,正在关闭服务器...")); $httpServers->stopServer($httpServer); });
# 导入Python标准库 import time from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _httpClients from m8test_java.com.m8test.script.GlobalVariables import _httpServers # 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _threads # 确保脚本在后台运行 _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) port = 8080 # 启动一个服务器 httpServer = _httpServers.startServer(port, lambda config: config.routing(lambda route: ( route.get("/", lambda call, s: ( (request := call.getRequest()), _console.log(f"[服务器] 收到来自 {request.getOriginConnectionPoint().getRemoteHost()} 的根路径请求"), # respondText 现在返回一个 Job,这成为 get 处理器块的返回值 call.getResponse().respondText(s, "你好,世界!来自 M8Test HTTP 服务器。", lambda it: it.getTextPlain()) )[-1]), route.get("/json", lambda call, s: ( _console.log("[服务器] 收到 /json 路径请求"), # 使用 f-string 和 time.time() 来构造JSON (jsonResponse := f'{{"status": "ok", "timestamp": {int(time.time() * 1000)}}}'), call.getResponse().respondText(s, jsonResponse, lambda it: it.getApplicationJson()) )[-1]) )) ) _console.log(f"HTTP 服务器已在 http://127.0.0.1:{port} 启动") # 创建客户端进行测试 httpClient = _httpClients.newClient(None) # 延迟1秒确保服务器已完全启动 scope.delay(1000).then(lambda s, v: ( _console.log("[客户端] 开始测试服务器..."), (req1 := httpClient.get(s, f"http://127.0.0.1:{port}/", None, None)), (req2 := httpClient.get(s, f"http://127.0.0.1:{port}/json", None, None)), # 等待所有请求完成 s.awaitAll([req1, req2]) )[-1]).then(lambda s, responses: ( (resp1Text := responses[0].getTextBody(s)), (resp2Text := responses[1].getTextBody(s)), s.awaitAll([resp1Text, resp2Text]) )[-1]).then(lambda s, bodies: ( _console.log("[客户端] 根路径响应: " + str(bodies[0])), _console.log("[客户端] /json 路径响应: " + str(bodies[1])), s.resolve(None) )[-1]).onError(lambda error: ( _console.error("[客户端] 测试失败: " + str(error)) )).onComplete(lambda: ( # 使用 lambda _: 以安全地接收可能存在的参数 _console.log("测试完成,正在关闭服务器..."), _httpServers.stopServer(httpServer) ))
# encoding: utf-8 # 确保脚本在后台运行 $threads.getMain.setBackground(true) scope = $coroutines.newScope(nil) port = 8080 # 启动一个服务器 httpServer = $httpServers.startServer(port) do |config| config.routing do |route| route.get("/") do |call, s| request = call.getRequest $console.log("[服务器] 收到来自 #{request.getOriginConnectionPoint.getRemoteHost} 的根路径请求") # respondText 现在返回一个 Job,这成为 get 处理器块的返回值 call.getResponse.respondText(s, "你好,世界!来自 M8Test HTTP 服务器.") do |it| it.getTextPlain end end route.get("/json") do |call, s| $console.log("[服务器] 收到 /json 路径请求") # 使用静态方法调用 System.currentTimeMillis jsonResponse = '{"status": "ok", "timestamp": ' + M8testJava::Java::Lang::System::N__currentTimeMillis().to_s + '}' call.getResponse.respondText(s, jsonResponse) do |it| it.getApplicationJson end end end end $console.log("HTTP 服务器已在 http://127.0.0.1:#{port} 启动") # 创建客户端进行测试 httpClient = $httpClients.newClient(nil) # 延迟1秒确保服务器已完全启动 scope.delay(1000).then do |s, v| $console.log("[客户端] 开始测试服务器...") req1 = httpClient.get(s, "http://127.0.0.1:#{port}/", nil, nil) req2 = httpClient.get(s, "http://127.0.0.1:#{port}/json", nil, nil) # 等待所有请求完成 s.awaitAll([req1, req2]) end.then do |s, responses| resp1Text = responses[0].getTextBody(s) resp2Text = responses[1].getTextBody(s) s.awaitAll([resp1Text, resp2Text]) end.then do |s, bodies| $console.log("[客户端] 根路径响应:", bodies[0]) $console.log("[客户端] /json 路径响应:", bodies[1]) s.resolve(nil) end.onError do |error| $console.error("[客户端] 测试失败:", error) end.onComplete do $console.log("测试完成,正在关闭服务器...") $httpServers.stopServer(httpServer) end

高级路由和请求处理

处理路径参数和查询参数

import com.m8test.script.GlobalVariables.* // 确保脚本在后台运行 _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) val port = 8081 val httpServer = _httpServers.startServer(port) { routing { // 同样移除 call 参数,使用 this get("/users/{name}") { s -> val request = getRequest() val name = request.getPathParameters()["name"]?.get(0) val role = request.getQueryParameters()["role"]?.get(0) ?: "guest" val responseText = "你好, $name! 你的角色是: $role" _console.log("[服务器] 正在响应: $responseText") getResponse().respondText(s, responseText, null) } } } _console.log("服务器已在 http://127.0.0.1:$port 启动") // 客户端测试 val httpClient = _httpClients.newClient(null) scope.delay(1000).then { s, v -> httpClient.get(s, "http://127.0.0.1:$port/users/M8Test?role=developer", null, null) }.then { s, response -> response.getTextBody(s) }.then { s, body -> _console.log("[客户端] 收到响应:", body) s.resolve(null) }.onError { error -> _console.error("[客户端] 测试失败:", error) }.onComplete { _httpServers.stopServer(httpServer) }
// 确保脚本在后台运行 $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) def port = 8081 def httpServer = $httpServers.startServer(port, { config -> config.routing({ route -> route.get("/users/{name}", { call, s -> def request = call.getRequest() def name = request.getPathParameters()["name"]?.get(0) def role = request.getQueryParameters()["role"]?.get(0) ?: "guest" def responseText = "你好, ${name}! 你的角色是: ${role}" $console.log("[服务器] 正在响应: ${responseText}") // 返回 respondText 返回的 Job call.getResponse().respondText(s, responseText, null) }) }) }) $console.log("服务器已在 http://127.0.0.1:${port} 启动") // 客户端测试 def httpClient = $httpClients.newClient(null) scope.delay(1000).then({ s, v -> httpClient.get(s, "http://127.0.0.1:${port}/users/M8Test?role=developer", null, null) }).then({ s, response -> response.getTextBody(s) }).then({ s, body -> $console.log("[客户端] 收到响应:", body) s.resolve(null) }).onError({ error -> $console.error("[客户端] 测试失败:", error) }).onComplete({ $httpServers.stopServer(httpServer) })
// 确保脚本在后台运行 $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); const port = 8081; const httpServer = $httpServers.startServer(port, config => { config.routing(route => { route.get("/users/{name}", (call, s) => { const request = call.getRequest(); const name = request.getPathParameters().get("name")?.get(0); const role = request.getQueryParameters().get("role")?.get(0) ?? "guest"; const responseText = "你好, " + name + "! 你的角色是: " + role; $console.log("[服务器] 正在响应: " + responseText); // respondText 返回 Job,必须返回 return call.getResponse().respondText(s, responseText, null); }); }); }); $console.log("服务器已在 http://127.0.0.1:" + port + " 启动"); // 客户端测试 const httpClient = $httpClients.newClient(null); scope.delay(1000).then((s, v) => { return httpClient.get(s, "http://127.0.0.1:" + port + "/users/M8Test?role=developer", null, null); }).then((s, response) => { return response.getTextBody(s); }).then((s, body) => { $console.log("[客户端] 收到响应:", body); return s.resolve(null); }).onError(error => { $console.error("[客户端] 测试失败:", error); }).onComplete(() => { $httpServers.stopServer(httpServer); });
-- 确保脚本在后台运行 _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) local port = 8081 local httpServer = _httpServers:startServer(port, function(config) config:routing(function(route) route:get("/users/{name}", function(call, s) local request = call:getRequest() -- ?. 安全调用转换为 'and' 逻辑 local nameList = request:getPathParameters():get("name") local name = nameList and nameList:get(1) -- Lua 列表/数组索引从 1 开始 -- ?. 和 ?: (Elvis) 运算符的转换 local roleList = request:getQueryParameters():get("role") local role = (roleList and roleList:get(1)) or "guest" local responseText = "你好, " .. tostring(name) .. "! 你的角色是: " .. tostring(role) _console:log("[服务器] 正在响应: " .. responseText) -- 返回 respondText 返回的 Job return call:getResponse():respondText(s, responseText, nil) end) end) end) _console:log("服务器已在 http://127.0.0.1:" .. tostring(port) .. " 启动") -- 客户端测试 local httpClient = _httpClients:newClient(nil) scope:delay(1000):_then(function(s, v) return httpClient:get(s, "http://127.0.0.1:" .. tostring(port) .. "/users/M8Test?role=developer", nil, nil) end):_then(function(s, response) return response:getTextBody(s) end):_then(function(s, body) _console:log("[客户端] 收到响应:", body) return s:resolve(nil) end):onError(function(error) if error ~= nil then _console:error("[客户端] 测试失败:", error:stackTraceToString()) else _console:error("[客户端] 测试失败,但未提供错误详情。") end end):onComplete(function() _httpServers:stopServer(httpServer) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\http\HttpServers $httpServers */ global $httpServers; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /** @var m8test_java\com\m8test\script\core\api\http\HttpClients $httpClients */ global $httpClients; // 确保脚本在后台运行 $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $port = 8081; $httpServer = $httpServers->startServer($port, function ($config) { $config->routing(function ($route) { $route->get(javaString("/users/{name}"), function ($call, $s) { global $console; $request = $call->getRequest(); $name = $request->getPathParameters()[javaString("name")]->get(0); // --- 修正点: 使用 isset 和三元运算符替代 '??' --- $queryParams = $request->getQueryParameters(); $roleParam = isset($queryParams[javaString("role")]) ? $queryParams[javaString("role")]->get(0) : null; $role = ($roleParam !== null) ? $roleParam : javaString("guest"); // --- 修正结束 --- $responseText = javaString("你好, {$name}! 你的角色是: {$role}"); $console->log(javaString("[服务器] 正在响应: {$responseText}")); // 返回 respondText 返回的 Job return $call->getResponse()->respondText($s, $responseText, null); }); }); }); $console->log(javaString("服务器已在 http://127.0.0.1:{$port} 启动")); // 客户端测试 $httpClient = $httpClients->newClient(null); $scope->delay(1000)->then(function ($s, $v) use ($httpClient, $port) { return $httpClient->get($s, javaString("http://127.0.0.1:{$port}/users/M8Test?role=developer"), null, null); })->then(function ($s, $response) { return $response->getTextBody($s); })->then(function ($s, $body) { global $console; $console->log(javaString("[客户端] 收到响应:"), $body); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("[客户端] 测试失败:"), $error); })->onComplete(function () use ($httpServers, $httpServer) { $httpServers->stopServer($httpServer); });
# 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _httpClients from m8test_java.com.m8test.script.GlobalVariables import _httpServers from m8test_java.com.m8test.script.GlobalVariables import _threads # 确保脚本在后台运行 _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) port = 8081 httpServer = _httpServers.startServer(port, lambda config: config.routing(lambda route: route.get("/users/{name}", lambda call, s: ( (request := call.getRequest()), # 安全地获取路径和查询参数 (path_params := request.getPathParameters()), (name_list := path_params.get("name")), (name := name_list[0] if name_list else None), (query_params := request.getQueryParameters()), (role_list := query_params.get("role")), (role_from_param := role_list[0] if role_list else None), (role := role_from_param if role_from_param is not None else "guest"), # 使用 f-string 进行字符串格式化 (responseText := f"你好, {name}! 你的角色是: {role}"), _console.log(f"[服务器] 正在响应: {responseText}"), # 返回 respondText 返回的 Job call.getResponse().respondText(s, responseText, None) )[-1]) ) ) _console.log(f"服务器已在 http://127.0.0.1:{port} 启动") # 客户端测试 httpClient = _httpClients.newClient(None) (scope.delay(1000).then( lambda s, v: httpClient.get(s, f"http://127.0.0.1:{port}/users/M8Test?role=developer", None, None)) .then(lambda s, response: response.getTextBody(s)) .then(lambda s, body: ( _console.log("[客户端] 收到响应:", body), s.resolve(None) )[-1]) .onError(lambda error: _console.error("[客户端] 测试失败:", error)) .onComplete(lambda: _httpServers.stopServer(httpServer)))
# encoding: utf-8 # 确保脚本在后台运行 $threads.getMain.setBackground(true) scope = $coroutines.newScope(nil) port = 8081 httpServer = $httpServers.startServer(port) do |config| config.routing do |route| route.get("/users/{name}") do |call, s| request = call.getRequest # 修复: 替换 &. 操作符 path_params_name = request.getPathParameters["name"] name = path_params_name ? path_params_name.get(0) : nil query_params_role = request.getQueryParameters["role"] role_val = query_params_role ? query_params_role.get(0) : nil role = role_val || "guest" responseText = "你好, #{name}! 你的角色是: #{role}" $console.log("[服务器] 正在响应: #{responseText}") # 返回 respondText 返回的 Job call.getResponse.respondText(s, responseText, nil) end end end $console.log("服务器已在 http://127.0.0.1:#{port} 启动") # 客户端测试 httpClient = $httpClients.newClient(nil) scope.delay(1000).then do |s, v| httpClient.get(s, "http://127.0.0.1:#{port}/users/M8Test?role=developer", nil, nil) end.then do |s, response| response.getTextBody(s) end.then do |s, body| $console.log("[客户端] 收到响应:", body) s.resolve(nil) end.onError do |error| $console.error("[客户端] 测试失败:", error) end.onComplete do $httpServers.stopServer(httpServer) end

处理 POST 请求体

import com.m8test.script.GlobalVariables.* // 确保脚本在后台运行 _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) val port = 8082 val httpServer = _httpServers.startServer(port) { routing { // post 处理器: HttpServerCall.(CoroutineScope) -> Job post("/submit") { s -> // getRequest() 是 HttpServerCall (this) 的方法 // getJsonBody 返回 Deferred<T> getRequest().getJsonBody(scope).then { s2, body -> _console.log("[服务器] 收到的 JSON Body:", body) val responseJson = """{"message": "数据已收到", "received": $body}""" // respondText 返回 Job, 而 then 的 lambda 需要返回 Deferred // 使用 toDeferred() 将 Job 转换为 Deferred<Unit> getResponse().respondText(s2, responseJson) { it.getApplicationJson() }.toDeferred() }.onError { error -> // 移除显式类型注解,让编译器自动推断为 com.m8test.script.core.api.exception.Throwable _console.error("[服务器] 处理请求体失败:", error) // onError 的 lambda 返回 Unit,但在异步链中我们通常只是执行副作用 // 这里直接响应错误信息 getResponse().respondText(s, "错误的请求体", null) } // 整个链式调用的结果是 Deferred (实现了 Job),符合 post 处理器的返回值要求 } } } _console.log("服务器已在 http://127.0.0.1:$port 启动") // 客户端测试 val httpClient = _httpClients.newClient(null) val postData = """{"user": "test", "id": 123}""" scope.delay(1000).then { s, v -> httpClient.postJson(s, "http://127.0.0.1:$port/submit", postData, null) }.then { s, response -> _console.log("[客户端] 响应状态码:", response.getStatusCode().getValue()) response.getTextBody(s) }.then { s, body -> _console.log("[客户端] 收到响应:", body) s.resolve(null) }.onError { error -> _console.error("[客户端] 测试失败:", error) }.onComplete { _httpServers.stopServer(httpServer) }
// 确保脚本在后台运行 $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) def port = 8082 def httpServer = $httpServers.startServer(port, { config -> config.routing({ route -> route.post("/submit", { call, s1 -> // post 处理器需要返回一个 Job。 // 整个 Deferred 链就是一个 Job,所以我们返回它。 call.getRequest().getJsonBody(scope).then({ s, body -> $console.log("[服务器] 收到的 JSON Body:", body) def responseJson = '{"message": "数据已收到", "received": ' + body.toString() + '}' call.getResponse().respondText(s, responseJson, { it.getApplicationJson() }) }).onError({ error -> $console.error("[服务器] 处理请求体失败:", error) call.getResponse().respondText(s1, "错误的请求体", null) }) }) }) }) $console.log("服务器已在 http://127.0.0.1:${port} 启动") // 客户端测试 def httpClient = $httpClients.newClient(null) def postData = '{"user": "test", "id": 123}' scope.delay(1000).then({ s, v -> httpClient.postJson(s, "http://127.0.0.1:${port}/submit", postData, null) }).then({ s, response -> $console.log("[客户端] 响应状态码:", response.getStatusCode().value) response.getTextBody(s) }).then({ s, body -> $console.log("[客户端] 收到响应:", body) s.resolve(null) }).onError({ error -> $console.error("[客户端] 测试失败:", error) }).onComplete({ $httpServers.stopServer(httpServer) })
// 确保脚本在后台运行 $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); const port = 8082; const httpServer = $httpServers.startServer(port, config => { config.routing(route => { route.post("/submit", (call, s1) => { // post 处理器需要返回一个 Job。 // 整个 Deferred 链就是一个 Job,所以我们直接返回它。 return call.getRequest().getJsonBody(scope).then((s, body) => { $console.log("[服务器] 收到的 JSON Body:", body); const responseJson = '{"message": "数据已收到", "received": ' + body.toString() + '}'; return call.getResponse().respondText(s, responseJson, it => it.getApplicationJson()); }).onError(error => { $console.error("[服务器] 处理请求体失败:", error); return call.getResponse().respondText(s1, "错误的请求体", null); }); }); }); }); $console.log("服务器已在 http://127.0.0.1:" + port + " 启动"); // 客户端测试 const httpClient = $httpClients.newClient(null); const postData = '{"user": "test", "id": 123}'; scope.delay(1000).then((s, v) => { return httpClient.postJson(s, "http://127.0.0.1:" + port + "/submit", postData, null); }).then((s, response) => { $console.log("[客户端] 响应状态码:", response.getStatusCode().getValue()); return response.getTextBody(s); }).then((s, body) => { $console.log("[客户端] 收到响应:", body); return s.resolve(null); }).onError(error => { $console.error("[客户端] 测试失败:", error); }).onComplete(() => { $httpServers.stopServer(httpServer); });
-- 确保脚本在后台运行 _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) local port = 8082 local httpServer = _httpServers:startServer(port, function(config) config:routing(function(route) route:post("/submit", function(call, s1) -- post 处理器需要返回一个 Job。 -- 整个 Deferred 链就是一个 Job,所以我们返回它。 return call:getRequest():getJsonBody(scope):_then(function(s, body) _console:log("[服务器] 收到的 JSON Body:", body) local responseJson = '{"message": "数据已收到", "received": ' .. tostring(body) .. '}' return call:getResponse():respondText(s, responseJson, function(it) return it:getApplicationJson() end) end):onError(function(error) if error ~= nil then _console:error("[服务器] 处理请求体失败:", error:stackTraceToString()) else _console:error("[服务器] 处理请求体失败,但未提供错误详情。") end return call:getResponse():respondText(s1, "错误的请求体", nil) end) end) end) end) _console:log("服务器已在 http://127.0.0.1:" .. tostring(port) .. " 启动") -- 客户端测试 local httpClient = _httpClients:newClient(nil) local postData = '{"user": "test", "id": 123}' scope:delay(1000):_then(function(s, v) return httpClient:postJson(s, "http://127.0.0.1:" .. tostring(port) .. "/submit", postData, nil) end):_then(function(s, response) _console:log("[客户端] 响应状态码:", response:getStatusCode().value) return response:getTextBody(s) end):_then(function(s, body) _console:log("[客户端] 收到响应:", body) return s:resolve(nil) end):onError(function(error) if error ~= nil then _console:error("[客户端] 测试失败:", error:stackTraceToString()) else _console:error("[客户端] 测试失败,但未提供错误详情。") end end):onComplete(function() _httpServers:stopServer(httpServer) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpServers $httpServers */ global $httpServers; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpClients $httpClients */ global $httpClients; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 确保脚本在后台运行 $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $port = 8082; $httpServer = $httpServers->startServer($port, function ($config) use ($scope) { $config->routing(function ($route) use ($scope) { $route->post(javaString("/submit"), function ($call, $s1) use ($scope) { // post 处理器需要返回一个 Job。 // 整个 Deferred 链就是一个 Job,所以我们返回它。 return $call->getRequest()->getJsonBody($scope)->then(function ($s, $body) use ($call) { global $console; $console->log(javaString("[服务器] 收到的 JSON Body:"), $body); $responseJson = javaString('{"message": "数据已收到", "received": ') . $body . '}'; return $call->getResponse()->respondText($s, $responseJson, function ($it) { return $it->getApplicationJson(); }); })->onError(function ($error) use ($call, $s1) { global $console; $console->error(javaString("[服务器] 处理请求体失败:"), $error); return $call->getResponse()->respondText($s1, javaString("错误的请求体"), null); }); }); }); }); // 修正点: 修复字符串拼接 $console->log(javaString("服务器已在 http://127.0.0.1:" . $port . " 启动")); // 客户端测试 $httpClient = $httpClients->newClient(null); $postData = javaString('{"user": "test", "id": 123}'); $scope->delay(1000)->then(function ($s, $v) use ($httpClient, $port, $postData) { return $httpClient->postJson($s, javaString("http://127.0.0.1:" . $port . "/submit"), $postData, null); })->then(function ($s, $response) { global $console; $console->log(javaString("[客户端] 响应状态码:"), $response->getStatusCode()->value); return $response->getTextBody($s); })->then(function ($s, $body) { global $console; $console->log(javaString("[客户端] 收到响应:"), $body); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("[客户端] 测试失败:"), $error); })->onComplete(function () use ($httpServer) { global $httpServers; $httpServers->stopServer($httpServer); });
# 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _httpClients from m8test_java.com.m8test.script.GlobalVariables import _httpServers from m8test_java.com.m8test.script.GlobalVariables import _threads # 确保脚本在后台运行 _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) port = 8082 httpServer = _httpServers.startServer(port, lambda config: config.routing(lambda route: # post 处理器需要返回一个 Job。 # 整个 Deferred 链就是一个 Job,所以我们返回它。 route.post("/submit", lambda call, s1: call.getRequest().getJsonBody(scope).then(lambda s, body: ( _console.log("[服务器] 收到的 JSON Body:", body), (responseJson := f'{{"message": "数据已收到", "received": {str(body)}}}'), call.getResponse().respondText(s, responseJson, lambda it: it.getApplicationJson()) )[-1]).onError(lambda error: ( _console.error("[服务器] 处理请求体失败:", error), call.getResponse().respondText(s1, "错误的请求体", None) )[-1]) ) ) ) _console.log(f"服务器已在 http://127.0.0.1:{port} 启动") # 客户端测试 httpClient = _httpClients.newClient(None) postData = '{"user": "test", "id": 123}' (scope.delay(1000).then(lambda s, v: httpClient.postJson(s, f"http://127.0.0.1:{port}/submit", postData, None)) .then(lambda s, response: ( _console.log("[客户端] 响应状态码:", response.getStatusCode().getValue()), response.getTextBody(s) )[-1]) .then(lambda s, body: ( _console.log("[客户端] 收到响应:", body), s.resolve(None) )[-1]) .onError(lambda error: _console.error("[客户端] 测试失败:", error)) .onComplete(lambda: _httpServers.stopServer(httpServer)))
# encoding: utf-8 # 确保脚本在后台运行 $threads.getMain.setBackground(true) scope = $coroutines.newScope(nil) port = 8082 httpServer = $httpServers.startServer(port) do |config| config.routing do |route| route.post("/submit") do |call, s1| # post 处理器需要返回一个 Job。 # 整个 Deferred 链就是一个 Job,所以我们返回它。 call.getRequest.getJsonBody(scope).then do |s, body| $console.log("[服务器] 收到的 JSON Body:", body) responseJson = '{"message": "数据已收到", "received": ' + body.to_s + '}' call.getResponse.respondText(s, responseJson) do |it| it.getApplicationJson end end.onError do |error| $console.error("[服务器] 处理请求体失败:", error) call.getResponse.respondText(s1, "错误的请求体", nil) end end end end $console.log("服务器已在 http://127.0.0.1:#{port} 启动") # 客户端测试 httpClient = $httpClients.newClient(nil) postData = '{"user": "test", "id": 123}' scope.delay(1000).then do |s, v| httpClient.postJson(s, "http://127.0.0.1:#{port}/submit", postData, nil) end.then do |s, response| $console.log("[客户端] 响应状态码:", response.getStatusCode.value) response.getTextBody(s) end.then do |s, body| $console.log("[客户端] 收到响应:", body) s.resolve(nil) end.onError do |error| $console.error("[客户端] 测试失败:", error) end.onComplete do $httpServers.stopServer(httpServer) end

托管静态文件

您可以轻松地将一个文件夹的内容作为静态网站托管。

import com.m8test.script.GlobalVariables.* // 确保脚本在后台运行 _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) // 1. 创建一个用于托管的文件夹和文件 val staticDir = _files.buildFile { setPath(_files.getFilesDir(), "www") } staticDir.mkdirs() val indexFile = _files.buildFile { setPath(staticDir.getAbsolutePath(), "index.html") } indexFile.writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8") val aboutFile = _files.buildFile { setPath(staticDir.getAbsolutePath(), "about.html") } aboutFile.writeText("<h1>关于我们</h1>", "UTF-8") _console.log("静态文件已创建于:", staticDir.getAbsolutePath()) val port = 8083 val httpServer = _httpServers.startServer(port) { routing { staticFiles("/", staticDir, "index.html", null) } } _console.log("静态文件服务器已在 http://127.0.0.1:$port 启动") // 客户端测试 val httpClient = _httpClients.newClient(null) scope.delay(1000).then { s, v -> val req1 = httpClient.get(s, "http://127.0.0.1:$port/", null, null) val req2 = httpClient.get(s, "http://127.0.0.1:$port/about.html", null, null) s.awaitAll(listOf(req1, req2)) }.then { s, responses -> val body1 = responses[0].getTextBody(s) val body2 = responses[1].getTextBody(s) s.awaitAll(listOf(body1, body2)) }.then { s, bodies -> _console.log("[客户端] / 响应:", bodies[0]) _console.log("[客户端] /about.html 响应:", bodies[1]) s.resolve(null) }.onError { error -> _console.error("[客户端] 测试失败:", error) }.onComplete { _httpServers.stopServer(httpServer) staticDir.deleteRecursively() _console.log("服务器已关闭,临时文件已清理。") }
// 确保脚本在后台运行 $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) // 1. 创建一个用于托管的文件夹和文件 def staticDir = $files.buildFile({ it.setPath($files.getFilesDir(), "www") }) staticDir.mkdirs() def indexFile = $files.buildFile({ it.setPath(staticDir.getAbsolutePath(), "index.html") }) indexFile.writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8") def aboutFile = $files.buildFile({ it.setPath(staticDir.getAbsolutePath(), "about.html") }) aboutFile.writeText("<h1>关于我们</h1>", "UTF-8") $console.log("静态文件已创建于:", staticDir.getAbsolutePath()) def port = 8083 def httpServer = $httpServers.startServer(port, { config -> config.routing({ route -> route.staticFiles("/", staticDir, "index.html", null) }) }) $console.log("静态文件服务器已在 http://127.0.0.1:${port} 启动") // 客户端测试 def httpClient = $httpClients.newClient(null) scope.delay(1000).then({ s, v -> def req1 = httpClient.get(s, "http://127.0.0.1:${port}/", null, null) def req2 = httpClient.get(s, "http://127.0.0.1:${port}/about.html", null, null) s.awaitAll([req1, req2]) }).then({ s, responses -> def body1 = responses[0].getTextBody(s) def body2 = responses[1].getTextBody(s) s.awaitAll([body1, body2]) }).then({ s, bodies -> $console.log("[客户端] / 响应:", bodies[0]) $console.log("[客户端] /about.html 响应:", bodies[1]) s.resolve(null) }).onError({ error -> $console.error("[客户端] 测试失败:", error) }).onComplete({ $httpServers.stopServer(httpServer) staticDir.deleteRecursively() $console.log("服务器已关闭,临时文件已清理。") })
// 确保脚本在后台运行 $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); // 1. 创建一个用于托管的文件夹和文件 const staticDir = $files.buildFile(it => { it.setPath($files.getFilesDir(), "www"); }); staticDir.mkdirs(); const indexFile = $files.buildFile(it => { it.setPath(staticDir.getAbsolutePath(), "index.html"); }); indexFile.writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8"); const aboutFile = $files.buildFile(it => { it.setPath(staticDir.getAbsolutePath(), "about.html"); }); aboutFile.writeText("<h1>关于我们</h1>", "UTF-8"); $console.log("静态文件已创建于:", staticDir.getAbsolutePath()); const port = 8083; const httpServer = $httpServers.startServer(port, config => { config.routing(route => { route.staticFiles("/", staticDir, "index.html", null); }); }); $console.log("静态文件服务器已在 http://127.0.0.1:" + port + " 启动"); // 客户端测试 const httpClient = $httpClients.newClient(null); scope.delay(1000).then((s, v) => { const req1 = httpClient.get(s, "http://127.0.0.1:" + port + "/", null, null); const req2 = httpClient.get(s, "http://127.0.0.1:" + port + "/about.html", null, null); return s.awaitAll([req1, req2]); }).then((s, responses) => { const body1 = responses[0].getTextBody(s); const body2 = responses[1].getTextBody(s); return s.awaitAll([body1, body2]); }).then((s, bodies) => { $console.log("[客户端] / 响应:", bodies[0]); $console.log("[客户端] /about.html 响应:", bodies[1]); return s.resolve(null); }).onError(error => { $console.error("[客户端] 测试失败:", error); }).onComplete(() => { $httpServers.stopServer(httpServer); staticDir.deleteRecursively(); $console.log("服务器已关闭,临时文件已清理。"); });
-- 确保脚本在后台运行 _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) -- 1. 创建一个用于托管的文件夹和文件 local staticDir = _files:buildFile(function(it) it:setPath(_files:getFilesDir(), "www") end) staticDir:mkdirs() local indexFile = _files:buildFile(function(it) it:setPath(staticDir:getAbsolutePath(), "index.html") end) indexFile:writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8") local aboutFile = _files:buildFile(function(it) it:setPath(staticDir:getAbsolutePath(), "about.html") end) aboutFile:writeText("<h1>关于我们</h1>", "UTF-8") _console:log("静态文件已创建于:", staticDir:getAbsolutePath()) local port = 8083 local httpServer = _httpServers:startServer(port, function(config) config:routing(function(route) route:staticFiles("/", staticDir, "index.html", nil) end) end) _console:log("静态文件服务器已在 http://127.0.0.1:" .. tostring(port) .. " 启动") -- 客户端测试 local httpClient = _httpClients:newClient(nil) scope:delay(1000):_then(function(s, v) local req1 = httpClient:get(s, "http://127.0.0.1:" .. tostring(port) .. "/", nil, nil) local req2 = httpClient:get(s, "http://127.0.0.1:" .. tostring(port) .. "/about.html", nil, nil) -- 修正1:awaitAll 需要一个 Java List, 而不是 Lua table。 return s:awaitAll(_iterables:listOf(req1, req2)) end):_then(function(s, responses) -- 修正2:Java List 是 0-based 索引。 local body1 = responses:get(0):getTextBody(s) local body2 = responses:get(1):getTextBody(s) -- 修正1:同样,这里也需要一个 Java List return s:awaitAll(_iterables:listOf(body1, body2)) end):_then(function(s, bodies) -- 修正2:Java List 是 0-based 索引。 _console:log("[客户端] / 响应:", bodies:get(0)) _console:log("[客户端] /about.html 响应:", bodies:get(1)) return s:resolve(nil) end):onError(function(error) if error ~= nil then _console:error("[客户端] 测试失败:", error:stackTraceToString()) else _console:error("[客户端] 测试失败,但未提供错误详情。") end end):onComplete(function() _httpServers:stopServer(httpServer) staticDir:deleteRecursively() _console:log("服务器已关闭,临时文件已清理。") end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\file\Files $files */ global $files; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpServers $httpServers */ global $httpServers; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpClients $httpClients */ global $httpClients; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; /** @var m8test_java\com\m8test\script\core\api\collections\Iterables $iterables */ global $iterables; // 确保脚本在后台运行 $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); // 1. 创建一个用于托管的文件夹和文件 $staticDir = $files->buildFile(function ($it) use ($files) { $it->setPath($files->getFilesDir(), javaString("www")); }); $staticDir->mkdirs(); $indexFile = $files->buildFile(function ($it) use ($staticDir) { $it->setPath($staticDir->getAbsolutePath(), javaString("index.html")); }); $indexFile->writeText(javaString("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>"), javaString("UTF-8")); $aboutFile = $files->buildFile(function ($it) use ($staticDir) { $it->setPath($staticDir->getAbsolutePath(), javaString("about.html")); }); $aboutFile->writeText(javaString("<h1>关于我们</h1>"), javaString("UTF-8")); $console->log(javaString("静态文件已创建于:"), $staticDir->getAbsolutePath()); $port = 8083; $httpServer = $httpServers->startServer($port, function ($config) use ($staticDir) { $config->routing(function ($route) use ($staticDir) { $route->staticFiles(javaString("/"), $staticDir, javaString("index.html"), null); }); }); // 修正点: 修复字符串拼接 $console->log(javaString("静态文件服务器已在 http://127.0.0.1:" . $port . " 启动")); // 客户端测试 $httpClient = $httpClients->newClient(null); $scope->delay(1000)->then(function ($s, $v) use ($httpClient, $port) { global $iterables; $req1 = $httpClient->get($s, javaString("http://127.0.0.1:" . $port . "/"), null, null); $req2 = $httpClient->get($s, javaString("http://127.0.0.1:" . $port . "/about.html"), null, null); return $s->awaitAll($iterables->listOf($req1, $req2)); })->then(function ($s, $responses) { global $iterables; $body1 = $responses->get(0)->getTextBody($s); $body2 = $responses->get(1)->getTextBody($s); return $s->awaitAll($iterables->listOf($body1, $body2)); })->then(function ($s, $bodies) { global $console; $console->log(javaString("[客户端] / 响应:"), $bodies->get(0)); $console->log(javaString("[客户端] /about.html 响应:"), $bodies->get(1)); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("[客户端] 测试失败:"), $error); })->onComplete(function () use ($httpServer, $staticDir) { global $console, $httpServers; $httpServers->stopServer($httpServer); $staticDir->deleteRecursively(); $console->log(javaString("服务器已关闭,临时文件已清理。")); });
# 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _files from m8test_java.com.m8test.script.GlobalVariables import _httpClients from m8test_java.com.m8test.script.GlobalVariables import _httpServers from m8test_java.com.m8test.script.GlobalVariables import _threads # 确保脚本在后台运行 _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) # 1. 创建一个用于托管的文件夹和文件 staticDir = _files.buildFile(lambda it: it.setPath(_files.getFilesDir(), "www")) staticDir.mkdirs() indexFile = _files.buildFile(lambda it: it.setPath(staticDir.getAbsolutePath(), "index.html")) indexFile.writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8") aboutFile = _files.buildFile(lambda it: it.setPath(staticDir.getAbsolutePath(), "about.html")) aboutFile.writeText("<h1>关于我们</h1>", "UTF-8") _console.log("静态文件已创建于:", staticDir.getAbsolutePath()) port = 8083 httpServer = _httpServers.startServer(port, lambda config: config.routing(lambda route: route.staticFiles("/", staticDir, "index.html", None)) ) _console.log(f"静态文件服务器已在 http://127.0.0.1:{port} 启动") # 客户端测试 httpClient = _httpClients.newClient(None) scope.delay(1000).then(lambda s, v: ( (req1 := httpClient.get(s, f"http://127.0.0.1:{port}/", None, None)), (req2 := httpClient.get(s, f"http://127.0.0.1:{port}/about.html", None, None)), s.awaitAll([req1, req2]) )[-1]).then(lambda s, responses: ( (body1 := responses[0].getTextBody(s)), (body2 := responses[1].getTextBody(s)), s.awaitAll([body1, body2]) )[-1]).then(lambda s, bodies: ( _console.log("[客户端] / 响应:", bodies[0]), _console.log("[客户端] /about.html 响应:", bodies[1]), s.resolve(None) )[-1]).onError(lambda error: _console.error("[客户端] 测试失败:", error) ).onComplete(lambda: ( _httpServers.stopServer(httpServer), staticDir.deleteRecursively(), _console.log("服务器已关闭,临时文件已清理。") ))
# encoding: utf-8 # 确保脚本在后台运行 $threads.getMain.setBackground(true) scope = $coroutines.newScope(nil) # 1. 创建一个用于托管的文件夹和文件 staticDir = $files.buildFile do |it| it.setPath($files.getFilesDir, "www") end staticDir.mkdirs indexFile = $files.buildFile do |it| it.setPath(staticDir.getAbsolutePath, "index.html") end indexFile.writeText("<h1>欢迎来到我的静态网站</h1><p>这是一个由 M8Test 脚本托管的页面。</p>", "UTF-8") aboutFile = $files.buildFile do |it| it.setPath(staticDir.getAbsolutePath, "about.html") end aboutFile.writeText("<h1>关于我们</h1>", "UTF-8") $console.log("静态文件已创建于:", staticDir.getAbsolutePath) port = 8083 httpServer = $httpServers.startServer(port) do |config| config.routing do |route| route.staticFiles("/", staticDir, "index.html", nil) end end $console.log("静态文件服务器已在 http://127.0.0.1:#{port} 启动") # 客户端测试 httpClient = $httpClients.newClient(nil) scope.delay(1000).then do |s, v| req1 = httpClient.get(s, "http://127.0.0.1:#{port}/", nil, nil) req2 = httpClient.get(s, "http://127.0.0.1:#{port}/about.html", nil, nil) s.awaitAll([req1, req2]) end.then do |s, responses| body1 = responses[0].getTextBody(s) body2 = responses[1].getTextBody(s) s.awaitAll([body1, body2]) end.then do |s, bodies| $console.log("[客户端] / 响应:", bodies[0]) $console.log("[客户端] /about.html 响应:", bodies[1]) s.resolve(nil) end.onError do |error| $console.error("[客户端] 测试失败:", error) end.onComplete do $httpServers.stopServer(httpServer) staticDir.deleteRecursively $console.log("服务器已关闭,临时文件已清理。") end

搭建 WebSocket 服务器

创建一个 WebSocket 端点来处理实时双向通信。

import com.m8test.script.GlobalVariables.* // 确保脚本在后台运行 _threads.getMain().setBackground(true) val scope = _coroutines.newScope(null) val port = 8084 val httpServer = _httpServers.startServer(port) { routing { // webSocket 处理器: WebSocketSession.(CoroutineScope) -> Job webSocket("/echo") { s1 -> _console.log("[服务器] 一个新的 WebSocket 客户端已连接!") // this 是 WebSocketSession setOnText { s, text -> _console.log("[服务器] 收到消息:", text) val reply = "服务器回显: $text" // sendText 返回 Job,满足 setOnText 要求 sendText(s, reply) } setOnClose { s, reason -> _console.warn("[服务器] 一个客户端已断开连接:", reason?.getMessage()) // resolve 返回 Deferred (也是 Job),满足 setOnClose 要求 s.resolve(null) } // 处理器本身返回一个 Job s1.resolve(null) } } } _console.log("WebSocket 服务器已在 ws://127.0.0.1:$port/echo 启动") // 客户端测试 val httpClient = _httpClients.newClient(null) scope.delay(1000).then { s, v -> // 这里的 then 期望返回 Deferred // httpClient.webSocket 返回 Job,需要转换为 Deferred httpClient.webSocket(s, "ws://127.0.0.1:$port/echo", null) { // this 是 WebSocketSession setOnOpen { ss -> _console.log("[客户端] WebSocket 已连接,发送消息...") sendText(ss, "Hello Echo Server!") } setOnText { ss, text -> _console.log("[客户端] 收到回显:", text) // 收到回显后关闭连接 // setOnText 需要返回 Job scope.delay(1000).then { sss, _ -> // close 返回 Job,但 then 需要 Deferred,所以要转换 close(sss, 1000, "测试完成").toDeferred() } } setOnClose { ss, reason -> _console.log("[客户端] 连接已关闭。") ss.resolve(null) } }.toDeferred() // 将 webSocket 返回的 Job 转为 Deferred }.then { s, v -> _console.log("客户端 WebSocket 会话结束。") s.resolve(null) }.onError { error -> _console.error("[客户端] WebSocket 测试失败:", error) }.onComplete { _console.log("测试完成,关闭服务器。") _httpServers.stopServer(httpServer) }
// 确保脚本在后台运行 $threads.getMain().setBackground(true) def scope = $coroutines.newScope(null) def port = 8084 def httpServer = $httpServers.startServer(port, { config -> config.routing({ route -> // webSocket 处理器需要返回一个 Job route.webSocket("/echo", { session, s1 -> $console.log("[服务器] 一个新的 WebSocket 客户端已连接!") session.setOnText({ s, text -> $console.log("[服务器] 收到消息:", text) def reply = "服务器回显: ${text}" // sendText 返回 Job,满足监听器要求 session.sendText(s, reply) }) session.setOnClose({ s, reason -> $console.warn("[服务器] 一个客户端已断开连接:", reason?.getMessage()) s.resolve(null) // 返回一个完成的 Job }) // 处理器本身返回一个完成的 Job,表示设置已完成 s1.resolve(null) }) }) }) $console.log("WebSocket 服务器已在 ws://127.0.0.1:${port}/echo 启动") // 客户端测试 def httpClient = $httpClients.newClient(null) scope.delay(1000).then({ s, v -> httpClient.webSocket(s, "ws://127.0.0.1:${port}/echo", null, { session -> session.setOnOpen({ ss -> $console.log("[客户端] WebSocket 已连接,发送消息...") session.sendText(ss, "Hello Echo Server!") }) session.setOnText({ ss, text -> $console.log("[客户端] 收到回显:", text) // 收到回显后关闭连接 session.close(ss, 1000, "测试完成") }) session.setOnClose({ ss, reason -> $console.log("[客户端] 连接已关闭。") ss.resolve(null) }) }) }).then({ s, v -> $console.log("客户端 WebSocket 会话结束。") s.resolve(null) }).onError({ error -> $console.error("[客户端] WebSocket 测试失败:", error) }).onComplete({ $console.log("测试完成,关闭服务器。") $httpServers.stopServer(httpServer) })
// 确保脚本在后台运行 $threads.getMain().setBackground(true); const scope = $coroutines.newScope(null); const port = 8084; const httpServer = $httpServers.startServer(port, config => { config.routing(route => { // webSocket 处理器需要返回一个 Job route.webSocket("/echo", session => { $console.log("[服务器] 一个新的 WebSocket 客户端已连接!"); session.setOnText((s, text) => { $console.log("[服务器] 收到消息:", text); const reply = "服务器回显: " + text; // sendText 返回 Job,满足监听器要求,必须返回 return session.sendText(s, reply); }); session.setOnClose((s, reason) => { $console.warn("[服务器] 一个客户端已断开连接:", reason?.getMessage()); // 返回一个完成的 Job return s.resolve(null); }); // 处理器本身返回一个完成的 Job,表示设置已完成 return scope.resolve(null); }); }); }); $console.log("WebSocket 服务器已在 ws://127.0.0.1:" + port + "/echo 启动"); // 客户端测试 const httpClient = $httpClients.newClient(null); scope.delay(1000).then((s, v) => { // httpClient.webSocket 返回一个 Job httpClient.webSocket(s, "ws://127.0.0.1:" + port + "/echo", null, (session, s1) => { session.setOnOpen(ss => { $console.log("[客户端] WebSocket 已连接,发送消息..."); return session.sendText(ss, "Hello Echo Server!"); }); session.setOnText((ss, text) => { $console.log("[客户端] 收到回显:", text); // 收到回显后关闭连接,close 返回 Job return session.close(ss, 1000, "测试完成"); }); session.setOnClose((ss, reason) => { $console.log("[客户端] 连接已关闭。"); return ss.resolve(null); }); }); return s.resolve(null); }).then((s, v) => { $console.log("客户端 WebSocket 会话结束。"); return s.resolve(null); }).onError(error => { $console.error("[客户端] WebSocket 测试失败:", error); }).onComplete(() => { $console.log("测试完成,关闭服务器。"); $httpServers.stopServer(httpServer); });
-- 确保脚本在后台运行 _threads:getMain():setBackground(true) local scope = _coroutines:newScope(nil) local port = 8084 local httpServer = _httpServers:startServer(port, function(config) config:routing(function(route) -- webSocket 处理器需要返回一个 Job route:webSocket("/echo", function(session, s1) _console:log("[服务器] 一个新的 WebSocket 客户端已连接!") session:setOnText(function(s, text) _console:log("[服务器] 收到消息:", text) local reply = "服务器回显: " .. text -- sendText 返回 Job,满足监听器要求 return session:sendText(s, reply) end) session:setOnClose(function(s, reason) _console:warn("[服务器] 一个客户端已断开连接:", reason and reason:getMessage()) return s:resolve(nil) -- 返回一个完成的 Job end) -- 处理器本身返回一个完成的 Job,表示设置已完成 return s1:resolve(nil) end) end) end) _console:log("WebSocket 服务器已在 ws://127.0.0.1:" .. tostring(port) .. "/echo 启动") -- 客户端测试 local httpClient = _httpClients:newClient(nil) scope:delay(1000):_then(function(s, v) return httpClient:webSocket(s, "ws://127.0.0.1:" .. tostring(port) .. "/echo", nil, function(session) session:setOnOpen(function(ss) _console:log("[客户端] WebSocket 已连接,发送消息...") return session:sendText(ss, "Hello Echo Server!") end) session:setOnText(function(ss, text) _console:log("[客户端] 收到回显:", text) -- 收到回显后关闭连接 return session:close(ss, 1000, "测试完成") end) session:setOnClose(function(ss, reason) _console:log("[客户端] 连接已关闭。") return ss:resolve(nil) end) end) end):_then(function(s, v) _console:log("客户端 WebSocket 会话结束。") return s:resolve(nil) end):onError(function(error) if error ~= nil then _console:error("[客户端] WebSocket 测试失败:", error:stackTraceToString()) else _console:error("[客户端] WebSocket 测试失败,但未提供错误详情。") end end):onComplete(function() _console:log("测试完成,关闭服务器。") _httpServers:stopServer(httpServer) end)
<?php /** @var m8test_java\com\m8test\script\core\api\thread\Threads $threads */ global $threads; /** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */ global $coroutines; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpServers $httpServers */ global $httpServers; /** @var m8test_java\com\m8test\script\core\api\net\http\HttpClients $httpClients */ global $httpClients; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 确保脚本在后台运行 $threads->getMain()->setBackground(true); $scope = $coroutines->newScope(function ($context) { $context->setDispatcher(function ($dispatchers) { return $dispatchers->getScriptMain(); }); }); $port = 8084; $httpServer = $httpServers->startServer($port, function ($config) { $config->routing(function ($route) { // webSocket 处理器需要返回一个 Job $route->webSocket(javaString("/echo"), function ($session, $s1) { global $console; $console->log(javaString("[服务器] 一个新的 WebSocket 客户端已连接!")); $session->setOnText(function ($s, $text) use ($session) { global $console; $console->log(javaString("[服务器] 收到消息:"), $text); $reply = javaString("服务器回显: ${text}"); // sendText 返回 Job,满足监听器要求 // [修正] 必须返回 Job 对象 return $session->sendText($s, $reply); }); $session->setOnClose(function ($s, $reason) { global $console; $console->warn(javaString("[服务器] 一个客户端已断开连接:"), $reason ? $reason->getMessage() : null); // [修正] 必须返回 Job 对象 return $s->resolve(null); }); // 处理器本身返回一个完成的 Job,表示设置已完成 return $s1->resolve(null); }); }); }); $console->log(javaString("WebSocket 服务器已在 ws://127.0.0.1:${port}/echo 启动")); // 客户端测试 $httpClient = $httpClients->newClient(null); $scope->delay(1000)->then(function ($s, $v) use ($httpClient, $port) { return $httpClient->webSocket($s, javaString("ws://127.0.0.1:${port}/echo"), null, function ($session) { $session->setOnOpen(function ($ss) use ($session) { global $console; $console->log(javaString("[客户端] WebSocket 已连接,发送消息...")); // [修正] 必须返回 Job 对象 return $session->sendText($ss, javaString("Hello Echo Server!")); }); $session->setOnText(function ($ss, $text) use ($session) { global $console; $console->log(javaString("[客户端] 收到回显:"), $text); // 收到回显后关闭连接 // [修正] 必须返回 Job 对象 return $session->close($ss, 1000, javaString("测试完成")); }); $session->setOnClose(function ($ss, $reason) { global $console; $console->log(javaString("[客户端] 连接已关闭。")); // [修正] 必须返回 Job 对象 return $ss->resolve(null); }); }); })->then(function ($s, $v) { global $console; $console->log(javaString("客户端 WebSocket 会话结束。")); return $s->resolve(null); })->onError(function ($error) { global $console; $console->error(javaString("[客户端] WebSocket 测试失败:"), $error); })->onComplete(function () use ($httpServer) { global $console, $httpServers; $console->log(javaString("测试完成,关闭服务器。")); $httpServers->stopServer($httpServer); });
# 导入所需的全局变量 from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _coroutines from m8test_java.com.m8test.script.GlobalVariables import _httpClients from m8test_java.com.m8test.script.GlobalVariables import _httpServers from m8test_java.com.m8test.script.GlobalVariables import _threads # 确保脚本在后台运行 _threads.getMain().setBackground(True) scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain())) port = 8084 httpServer = _httpServers.startServer(port, lambda config: config.routing(lambda route: # webSocket 处理器需要返回一个 Job route.webSocket("/echo", lambda session, s1: ( _console.log("[服务器] 一个新的 WebSocket 客户端已连接!"), session.setOnText(lambda s, text: ( _console.log("[服务器] 收到消息:", text), (reply := f"服务器回显: {text}"), # sendText 返回 Job,满足监听器要求 session.sendText(s, reply) )[-1]), session.setOnClose(lambda s, reason: ( # reason 可能为 null,所以进行检查 _console.warn("[服务器] 一个客户端已断开连接:", reason.getMessage() if reason else "No reason given"), s.resolve(None) # 返回一个完成的 Job )[-1]), # 处理器本身返回一个完成的 Job,表示设置已完成 s1.resolve(None) )[-1]) ) ) _console.log(f"WebSocket 服务器已在 ws://127.0.0.1:{port}/echo 启动") # 客户端测试 httpClient = _httpClients.newClient(None) (scope.delay(1000) .then(lambda s, v: httpClient.webSocket(s, f"ws://127.0.0.1:{port}/echo", None, lambda session: ( session.setOnOpen(lambda ss: ( _console.log("[客户端] WebSocket 已连接,发送消息..."), session.sendText(ss, "Hello Echo Server!") )[-1]), session.setOnText(lambda ss, text: ( _console.log("[客户端] 收到回显:", text), # 收到回显后关闭连接 session.close(ss, 1000, "测试完成") )[-1]), session.setOnClose(lambda ss, reason: ( _console.log("[客户端] 连接已关闭。"), ss.resolve(None) )[-1]) ))) .then(lambda s, v: ( _console.log("客户端 WebSocket 会话结束。"), s.resolve(None) )[-1]) .onError(lambda error: _console.error("[客户端] WebSocket 测试失败:", error)) .onComplete(lambda: ( _console.log("测试完成,关闭服务器。"), _httpServers.stopServer(httpServer) )))
# encoding: utf-8 # 确保脚本在后台运行 $threads.getMain.setBackground(true) scope = $coroutines.newScope(nil) port = 8084 httpServer = $httpServers.startServer(port) do |config| config.routing do |route| # webSocket 处理器需要返回一个 Job route.webSocket("/echo") do |session, s1| $console.log("[服务器] 一个新的 WebSocket 客户端已连接!") session.setOnText do |s, text| $console.log("[服务器] 收到消息:", text) reply = "服务器回显: #{text}" # sendText 返回 Job,满足监听器要求 session.sendText(s, reply) end session.setOnClose do |s, reason| # 修复: 替换 &. 操作符 msg = reason ? reason.getMessage : nil $console.warn("[服务器] 一个客户端已断开连接:", msg) s.resolve(nil) # 返回一个完成的 Job end # 处理器本身返回一个完成的 Job,表示设置已完成 s1.resolve(nil) end end end $console.log("WebSocket 服务器已在 ws://127.0.0.1:#{port}/echo 启动") # 客户端测试 httpClient = $httpClients.newClient(nil) scope.delay(1000).then do |s, v| httpClient.webSocket(s, "ws://127.0.0.1:#{port}/echo", nil) do |session| session.setOnOpen do |ss| $console.log("[客户端] WebSocket 已连接,发送消息...") session.sendText(ss, "Hello Echo Server!") end session.setOnText do |ss, text| $console.log("[客户端] 收到回显:", text) # 收到回显后关闭连接 session.close(ss, 1000, "测试完成") end session.setOnClose do |ss, reason| $console.log("[客户端] 连接已关闭。") ss.resolve(nil) end end end.then do |s, v| $console.log("客户端 WebSocket 会话结束。") s.resolve(nil) end.onError do |error| $console.error("[客户端] WebSocket 测试失败:", error) end.onComplete do $console.log("测试完成,关闭服务器。") $httpServers.stopServer(httpServer) end
09 December 2025