Func Stateful 服务端开发指南
Func Stateful 服务端开发指南
本教程演示如何使用 C#, Java, JavaScript, Python 编写 Func Stateful 应用的服务端代码并将其部署在 UOS 平台上。 请先选择您所需要使用的语言,使用示例中的代码进行打包之后,参考 「项目的部署与运行」 进行测试。
C#
示例代码:
using System.Net;
using System.Text;
const string url = "http://+:8899/";
var listener = new HttpListener();
listener.Prefixes.Add(url);
listener.Start();
Console.WriteLine("Listening for connections on {0}", url);
while (true)
{
var ctx = await listener.GetContextAsync();
var req = ctx.Request;
var res = ctx.Response;
// Debug
Console.WriteLine(req.Url?.ToString());
Console.WriteLine(req.HttpMethod);
Console.WriteLine(req.RemoteEndPoint?.Address);
Console.WriteLine(req.UserHostName);
Console.WriteLine(req.UserAgent);
// Process request and send response
var responseData = $"Request Information:\n" +
$"URL: {req.Url}\n" +
$"HttpMethod: {req.HttpMethod}\n" +
$"UserHostName: {req.UserHostName}\n" +
$"UserAgent: {req.UserAgent}\n" +
$"Remote IP Address: {req.RemoteEndPoint?.Address}\n" +
$"Headers:\n";
for (var index = 0; index < req.Headers.Count; index++)
{
var headerName = req.Headers[index];
responseData += $"{headerName}: {req.Headers[headerName]}\n";
}
var buffer = Encoding.UTF8.GetBytes(responseData);
res.ContentLength64 = buffer.Length;
await using var output = res.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}项目的创建与打包
首先需要确保系统安装了 .NET SDK。若未安装可以前往 官方 .NET 下载页 下载并安装 .NET SDK(建议下载6.0或者7.0)。
通过指令检查是否安装成功:
dotnet --list-sdks
//example: 6.0.414 [/usr/local/share/dotnet/sdk]通过以下命令新建一个dotnet项目:
dotnet new console -n func-stateful使用示例代码替换生成项目中的 Program.cs 文件代码。
通过以下命令对项目进行编译,编译结果输出到 project 目录中:
cd func-stateful
dotnet publish -o project -c Release -r linux-x64 --no-self-contained进入 project 目录,将目录下所有的文件压缩成 zip 格式的压缩包。
cd project
zip -r func-stateful.zip ./*点击 New Solution 创建一个新的 dotnet 项目。
在左侧选择 Console Application, 随后填写 Solution Name 和 Project Name 为 func-stateful, 选择 Solution directory 到任意指定位置, 勾选上 Put solution and project in the same directory。 同时根据系统所安装的 SDK 版本进行选择, 然后点击 Create 完成创建。
使用示例代码替换生成项目中的 Program.cs 文件代码。
随后右键点击左边的 func-stateful 项目后在菜单中选择 publish 选项。
在弹出来的 Publish To 选项中选择 Local Folder。
选择 Target Location 目标目录到任意指定位置, Target Runtime 目标运行时选择 linux-x64 ,随后点击 Run 运行。
将上一步生成文件所在目录下所有文件打包成 zip 格式的压缩包。
Java
示例代码:
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.List;
import java.util.Map;
public class SimpleHttpServer {
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(8899), 0);
System.out.println("Listening for connections on http://0.0.0.0:8899");
server.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange exchange) throws IOException {
// Debug
URI requestURI = exchange.getRequestURI();
String httpMethod = exchange.getRequestMethod();
String remoteAddress = exchange.getRemoteAddress().getAddress().getHostAddress();
String userHostName = exchange.getRemoteAddress().getHostName();
List<String> userAgent = exchange.getRequestHeaders().get("User-Agent");
System.out.println("URL: " + requestURI);
System.out.println("HttpMethod: " + httpMethod);
System.out.println("Remote IP Address: " + remoteAddress);
System.out.println("UserHostName: " + userHostName);
System.out.println("UserAgent: " + (userAgent != null ? userAgent.get(0) : "Unknown"));
// Process request and send response
StringBuilder responseData = new StringBuilder();
responseData.append("Request Information:\n")
.append("URL: ").append(requestURI).append("\n")
.append("HttpMethod: ").append(httpMethod).append("\n")
.append("UserHostName: ").append(userHostName).append("\n")
.append("UserAgent: ").append(userAgent != null ? userAgent.get(0) : "Unknown").append("\n")
.append("Remote IP Address: ").append(remoteAddress).append("\n")
.append("Headers:\n");
for (Map.Entry<String, List<String>> entry : exchange.getRequestHeaders().entrySet()) {
responseData.append(entry.getKey()).append(": ").append(String.join(", ", entry.getValue())).append("\n");
}
byte[] responseBytes = responseData.toString().getBytes();
exchange.sendResponseHeaders(200, responseBytes.length);
OutputStream os = exchange.getResponseBody();
os.write(responseBytes);
os.close();
}
});
server.setExecutor(null); // creates a default executor
server.start();
}
}项目的创建与打包
将上述示例代码编译成 「SimpleHttpServer.jar」 后,使用以下命令进行打包:
zip SimpleHttpServer.zip SimpleHttpServer.jarJavaScript
示例代码:
const express = require('express');
const app = express();
app.use((req, res, next) => {
// Debug
console.log('URL: ', req.url);
console.log('Method: ', req.method);
console.log('Remote IP Address: ', req.ip);
console.log('UserHostName: ', req.hostname);
console.log('UserAgent: ', req.get('User-Agent'));
// Process request and send response
let responseData = 'Request Information:\r\n' +
'URL: ' + req.url + '\r\n' +
'HttpMethod: ' + req.method + '\r\n' +
'UserHostName: ' + req.hostname + '\r\n' +
'UserAgent: ' + req.get('User-Agent') + '\r\n' +
'Remote IP Address: ' + req.ip + '\r\n' +
'Headers:\r\n';
for (const [headerName, headerValue] of Object.entries(req.headers)) {
responseData += headerName + ':' + headerValue + '\r\n';
}
res.setHeader('Content-Type', 'text/plain');
res.send(responseData);
});
app.listen(8899, '0.0.0.0', () => {
console.log('Listening for connections on http://0.0.0.0:8899/');
});项目的创建与打包
首先需要确保系统安装了 Node。通过以下命令新建一个 node 项目,并且安装示例中所使用到的库:
npm init -y
npm install express在项目目录中创建 index.js 文件,并使用示例代替换文件内容。通过以下命令对项目以及依赖代码进行打包:
zip -r node.zip ./*Python
示例代码:
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def handle_request():
# Debug
print(f"URL: {request.url}")
print(f"Method: {request.method}")
print(f"Remote IP Address: {request.remote_addr}")
print(f"UserHostName: {request.host}")
print(f"UserAgent: {request.headers.get('User-Agent')}")
# Process request and send response
response_data = f"Request Information:\n" \
f"URL: {request.url}\n" \
f"HttpMethod: {request.method}\n" \
f"UserHostName: {request.host}\n" \
f"UserAgent: {request.headers.get('User-Agent')}\n" \
f"Remote IP Address: {request.remote_addr}\n" \
f"Headers:\n"
for header, value in request.headers.items():
response_data += f"{header}: {value}\n"
return response_data, 200, {'Content-Type': 'text/plain'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8899)
print(f"Listening for connections on http://0.0.0.0:8899/")项目的创建与打包
首先需要确保系统安装了 Python。通过以下命令新建一个文件夹作为项目目录,并且安装示例中所使用到的库到此文件夹下的 「python_modules」 目录:
mkdir python-demo && cd python-demo
pip install --target=./python_modules Flask在项目目录中创建 app.py 文件,并使用示例代替换文件内容。通过以下命令对项目以及依赖代码进行打包:
zip -r python.zip ./*项目的部署与运行
在完成项目打包后,就可以参考 示例教程 中的步骤进行部署。
需要注意的是,在上传和制作镜像的过程中,需要根据开发过程中所使用的编程语言以及对应版本选择相应的服务器操作系统,并按照需要填写需要执行文件名添加权限。
此外,在启动镜像配置时,也需要根据实际开发的项目修改「入口程序启动命令」(例如,“func-stateful",“java -jar SimpleHttpServer.jar",“node index.js",“python app.py")。
在启动完服务器之后,就可以根据服务器的IP和端口进行访问,测试服务器运行的情况。
以 Postman 测试为例,服务器成功创建后,访问对应的IP和端口服务器会返回图中类似的信息。