跳到主要内容

网络编程

网络编程是现代应用开发的重要组成部分。本章将详细介绍 Sii 2 中的 HTTP 客户端和服务器功能,以及如何构建网络应用。

网络编程概述

Sii 2 通过运行时服务器提供网络编程能力,包括:

  • HTTP 客户端:发送 HTTP 请求
  • HTTP 服务器:创建 HTTP 服务器
  • 路由处理:处理不同的 HTTP 路由
  • 请求响应:处理 HTTP 请求和响应

HTTP 客户端

sii.get()

发送 GET 请求:

// 基本 GET 请求
let response: obj = sii.get("https://api.example.com/data");

// 访问响应数据
let status: int = response.status;
let body: obj = response.body;
let headers: obj = response.headers;

sii.post()

发送 POST 请求:

// POST 请求,发送 JSON 数据
crob data = new Object();
data.name = "Alice";
data.age = 25;

let response: obj = sii.post("https://api.example.com/users", data);

// 处理响应
if (response.status == 200) {
sii.io.print("User created successfully");
} else {
sii.io.print("Error: " + string(response.status));
}

HTTP 请求示例

func fetchUserData(userId: int): obj | void {
let url: string = "https://api.example.com/users/" + string(userId);
let response: obj = sii.get(url);

if (response.status == 200) {
back response.body;
} else {
sii.error("Failed to fetch user: " + string(response.status));
back;
}
}

// 使用
let user: obj | void = fetchUserData(123);
if (typeins(user) == "obj") {
let userData: obj = user as obj;
sii.io.print("User: " + userData.name);
}

HTTP 服务器

sii.listen()

创建 HTTP 服务器并监听端口:

// 监听端口 3000
sii.listen(3000);

// 服务器启动后,可以注册路由处理请求

路由注册

HTTP 路由通过 sii.get(), sii.post() 等方法注册,handler 参数是函数名字符串:

// 定义处理函数
func handleGetUsers(request: obj): obj {
crob response = new Object();
response.status = 200;
response.body = "User list";
back response;
}

func handleCreateUser(request: obj): obj {
let userData: obj = request.body;
// 处理用户创建逻辑
crob response = new Object();
response.status = 201;
response.body = "User created";
back response;
}

// 注册 GET 路由(handler 是函数名字符串)
sii.get("/users", "handleGetUsers");

// 注册 POST 路由
sii.post("/users", "handleCreateUser");

请求对象

请求对象包含以下信息:

func handleRequest(request: obj): obj {
// 请求方法
let method: string = request.method; // "GET", "POST", etc.

// 请求路径
let path: string = request.url;

// 请求头
let headers: obj = request.headers;

// 请求体(POST/PUT 请求)
let body: obj = request.body;

// 查询参数(如果支持)
// let query: obj = request.query;

// 处理请求...
crob response = new Object();
response.status = 200;
response.body = "OK";
back response;
}

响应对象

响应对象包含以下字段:

func createResponse(status: int, body: obj, headers: obj): obj {
crob response = new Object();
response.status = status;
response.body = body;
response.headers = headers;
back response;
}

响应辅助函数

sii.respText()

返回文本响应:

func handleTextRequest(request: obj): obj {
let response: obj = sii.respText(200, "Hello, World!");
back response;
}

sii.respJson()

返回 JSON 响应:

func handleJsonRequest(request: obj): obj {
crob data = new Object();
data.message = "Success";
data.timestamp = sii.now();

let response: obj = sii.respJson(200, data);
back response;
}

sii.respHtml()

返回 HTML 响应:

func handleHtmlRequest(request: obj): obj {
let html: string = "<html><body><h1>Hello, Sii 2!</h1></body></html>";
let response: obj = sii.respHtml(200, html);
back response;
}

完整 HTTP 服务器示例

示例 1:简单的 API 服务器

// 用户数据存储(简化版,实际应使用数据库)
let users: arr = new Array();

// 定义处理函数
func handleGetUsers(request: obj): obj {
back sii.respJson(200, users);
}

func handleGetUser(request: obj): obj {
// 注意:路径参数需要通过 request 对象获取
let userId: int = request.params.id.toInt();

// 查找用户(简化版)
let user: obj | void = findUser(userId);
if (typeins(user) == "obj") {
back sii.respJson(200, user as obj);
} else {
back sii.respText(404, "User not found");
}
}

func handleCreateUser(request: obj): obj {
let userData: obj = request.body;

// 验证数据
if (userData.name.length() == 0) {
back sii.respText(400, "Name is required");
}

// 创建用户
crob newUser = new Object();
newUser.id = users.length() + 1;
newUser.name = userData.name;
newUser.email = userData.email;

// 添加用户到数组
users[users.length()] = newUser;

back sii.respJson(201, newUser);
}

func handleUpdateUser(request: obj): obj {
let userId: int = request.params.id.toInt();
let userData: obj = request.body;

// 查找并更新用户
let user: obj | void = findUser(userId);
if (typeins(user) == "obj") {
let existingUser: obj = user as obj;
existingUser.name = userData.name;
existingUser.email = userData.email;
back sii.respJson(200, existingUser);
} else {
back sii.respText(404, "User not found");
}
}

func handleDeleteUser(request: obj): obj {
let userId: int = request.params.id.toInt();

// 删除用户(简化版)
let success: bool = deleteUser(userId);
if (success) {
back sii.respText(200, "User deleted");
} else {
back sii.respText(404, "User not found");
}
}

// 启动服务器
sii.listen(8080);

// 注册路由(handler 是函数名字符串)
sii.get("/users", "handleGetUsers");
sii.get("/users/:id", "handleGetUser");
sii.post("/users", "handleCreateUser");
sii.put("/users/:id", "handleUpdateUser");
sii.delete("/users/:id", "handleDeleteUser");

// 辅助函数
func findUser(id: int): obj | void {
forloop (let i: int = 0; i < users.length(); i.getUp(1)) {
let user: obj = users[i];
if (user.id == id) {
back user;
}
}
back;
}

func deleteUser(id: int): bool {
forloop (let i: int = 0; i < users.length(); i.getUp(1)) {
let user: obj = users[i];
if (user.id == id) {
rmv users[i]; // 使用 rmv 语句删除元素
back true;
}
}
back false;
}

示例 2:文件服务器

// 定义处理函数
func handleGetFile(request: obj): obj {
let filename: string = request.params.filename;
let filePath: string = sii.pathJoin("./files", filename);

if (!sii.exists(filePath)) {
back sii.respText(404, "File not found");
}

let content: string = sii.readText(filePath);
back sii.respText(200, content);
}

func handleSaveFile(request: obj): obj {
let filename: string = request.params.filename;
let filePath: string = sii.pathJoin("./files", filename);
let content: string = request.body.content;

sii.writeText(filePath, content);
back sii.respText(200, "File saved");
}

// 启动文件服务器
sii.listen(3000);

// 注册路由
sii.get("/files/:filename", "handleGetFile");
sii.post("/files/:filename", "handleSaveFile");

HTTP 客户端示例

示例 1:API 客户端

func fetchApiData(endpoint: string): obj | void {
let url: string = "https://api.example.com" + endpoint;
let response: obj = sii.get(url);

if (response.status == 200) {
back response.body;
} else {
sii.error("API request failed: " + string(response.status));
back;
}
}

// 使用
let data: obj | void = fetchApiData("/users");
if (typeins(data) == "obj") {
let users: arr = data.users as arr;
sii.io.print("Found " + string(users.length()) + " users");
}

示例 2:数据提交

func submitData(url: string, data: obj): bool {
let response: obj = sii.post(url, data);

if (response.status == 200 || response.status == 201) {
sii.log("Data submitted successfully");
back true;
} else {
sii.error("Failed to submit data: " + string(response.status));
back false;
}
}

// 使用
crob formData = new Object();
formData.name = "Alice";
formData.email = "alice@example.com";

let success: bool = submitData("https://api.example.com/submit", formData);

错误处理

HTTP 错误处理

func safeHttpGet(url: string): obj | void {
let response: obj = sii.get(url);

if (response.status >= 200 && response.status < 300) {
back response.body;
} else if (response.status == 404) {
sii.error("Resource not found: " + url);
back;
} else if (response.status >= 500) {
sii.error("Server error: " + string(response.status));
back;
} else {
sii.error("Request failed: " + string(response.status));
back;
}
}

超时处理

// 注意:Sii 2 可能不直接支持超时设置
// 需要在运行时服务器层面处理
func requestWithTimeout(url: string, timeoutMs: int): obj | void {
// 实现超时逻辑(如果支持)
let response: obj = sii.get(url);
back response;
}

网络编程最佳实践

1. 错误处理

始终检查 HTTP 响应状态:

func safeHttpRequest(url: string): obj | void {
let response: obj = sii.get(url);

if (response.status != 200) {
sii.error("HTTP Error: " + string(response.status));
back;
}

back response.body;
}

2. 请求验证

验证请求数据:

func validateRequest(request: obj): bool {
if (request.method == "POST" || request.method == "PUT") {
if (typeins(request.body) != "obj") {
back false;
}
}
back true;
}

3. 响应格式化

使用统一的响应格式:

func createApiResponse(success: bool, data: obj, message: string): obj {
crob response = new Object();
response.success = success;
response.data = data;
response.message = message;
response.timestamp = sii.now();
back sii.respJson(if (success) { 200 } else { 400 }, response);
}

4. 路由组织

按功能组织路由:

// users.sii - 用户相关路由
func setupUserRoutes(): void {
sii.get("/users", "handleGetUsers");
sii.post("/users", "handleCreateUser");
sii.get("/users/:id", "handleGetUser");
sii.put("/users/:id", "handleUpdateUser");
sii.delete("/users/:id", "handleDeleteUser");
}

// main.sii
setupUserRoutes();
sii.listen(8080);

小结

本章介绍了 Sii 2 中的网络编程:

  • HTTP 客户端get(), post() 等请求方法
  • HTTP 服务器listen(), route() 创建服务器
  • 请求处理:处理 HTTP 请求和响应
  • 响应辅助respText(), respJson(), respHtml()
  • 错误处理:HTTP 错误处理机制
  • 最佳实践:如何构建健壮的网络应用

下一章我们将学习编译和构建,了解如何使用 Sii 2 编译器。