HTTP编程基础
HTTP(超文本传输协议)是互联网上应用最广泛的应用层协议,仓颉语言通过stdx.net.http
模块提供了完整的HTTP编程支持。
HTTP协议特性
仓颉支持的HTTP协议具有以下特点:
- 请求-响应模型:客户端发送请求,服务端返回响应
- 无状态协议:每个请求独立处理,不保留上下文
- 多种方法:支持GET、POST、PUT、DELETE等标准方法
- 版本兼容:完整支持HTTP/1.1和HTTP/2.0协议
核心组件
仓颉的HTTP编程围绕几个核心类构建:
- HttpRequest/HttpResponse:表示HTTP请求和响应
- Client/Server:客户端和服务端抽象
- HttpHeaders:处理HTTP头部信息
- HttpContext:封装请求上下文
HTTP服务端开发
创建HTTP服务端的基本步骤:
import stdx.net.http.* import std.time.* import std.sync.* func startServer() { let server = ServerBuilder() .addr("127.0.0.1") .port(8080) .build() // 注册路由处理器 server.distributor.register("/hello", { ctx => ctx.responseBuilder .status(200) .body("Hello Cangjie!") }) server.serve() } main() { spawn { startServer() } sleep(Duration.second * 5) }
关键点说明:
- 使用
ServerBuilder
构建服务实例 - 通过
register
方法注册路由处理逻辑 HttpContext
提供请求/响应构建能力serve()
启动服务监听
HTTP客户端开发
HTTP客户端请求示例:
import stdx.net.http.* func httpClientDemo() { let client = ClientBuilder().build() let response = client.get("http://127.0.0.1:8080/hello") let buffer = Array<Byte>(1024, repeat: 0) let length = response.body.read(buffer) println(String.fromUtf8(buffer[..length])) } main() { httpClientDemo() }
客户端核心功能:
ClientBuilder
创建客户端实例- 支持GET/POST/PUT/DELETE等方法
- 响应体可通过流式接口读取
- 自动处理连接池和资源管理
WebSocket编程详解
WebSocket是建立在TCP上的全双工通信协议,仓颉通过WebSocket
类提供支持。
WebSocket协议特点
- 单一TCP连接:避免HTTP的重复握手开销
- 双向通信:服务端可主动推送消息
- 低延迟:相比HTTP轮询更高效
- 帧式传输:数据以帧为单位组织
核心概念
仓颉WebSocket编程的核心抽象:
- WebSocket类:封装连接和帧操作
- 帧类型:
- 控制帧:Close/Ping/Pong
- 数据帧:Text/Binary/Continuation
- 握手升级:从HTTP协议升级到WebSocket
WebSocket服务端开发
服务端实现示例:
import stdx.net.http.* import std.collection.* import stdx.log.* func startWebSocketServer() { let server = ServerBuilder() .addr("127.0.0.1") .port(0) .build() server.distributor.register("/ws", handler) server.serve() } func handler(ctx: HttpContext) { let ws = WebSocket.upgradeFromServer(ctx, subProtocols: ArrayList(["proto1", "proto2"]), userFunc: { req => let headers = HttpHeaders() headers.add("Custom-Header", "value") headers }) // 消息处理循环 while (true) { let frame = ws.read() match (frame.frameType) { case TextWebFrame => println("Received: ${String.fromUtf8(frame.payload)}") ws.write(TextWebFrame, "Echo: ".toArray() + frame.payload) case CloseWebFrame => ws.write(CloseWebFrame, frame.payload) break case _ => // 忽略其他帧类型 } } ws.closeConn() }
关键步骤:
- 通过
upgradeFromServer
完成协议升级 - 处理各种帧类型实现业务逻辑
- 使用
write
方法发送响应帧 - 妥善处理连接关闭
WebSocket客户端开发
客户端实现示例:
import stdx.net.http.* import stdx.encoding.url.* import std.collection.* func websocketClient() { let client = ClientBuilder().build() let url = URL.parse("ws://127.0.0.1:8080/ws") let (websocket, _) = WebSocket.upgradeFromClient( client, url, subProtocols: ArrayList(["proto1"]), headers: HttpHeaders().add("X-Token", "abc123") ) // 发送文本消息 websocket.write(TextWebFrame, "Hello Server".toArray()) // 接收响应 let frame = websocket.read() if (frame.frameType == TextWebFrame) { println("Server response: ${String.fromUtf8(frame.payload)}") } // 优雅关闭 websocket.writeCloseFrame(status: 1000) websocket.closeConn() }
客户端关键点:
- 使用
upgradeFromClient
建立连接 - 支持子协议协商和自定义头部
- 帧的读写操作是核心API
- 应遵循协议规范关闭连接
高级特性与最佳实践
HTTP高级功能
- 中间件管道:
server.use({ ctx, next => println("Request to ${ctx.request.path}") next(ctx) println("Response status: ${ctx.response.status}") })
- 路由分组:
let apiGroup = server.group("/api") apiGroup.register("/users", userHandler) apiGroup.register("/products", productHandler)
- 静态文件服务:
server.distributor.registerStatic("/static", "public")
WebSocket高级特性
- 二进制数据传输:
let binaryData = [0x01, 0x02, 0x03] as Array<UInt8> websocket.write(BinaryWebFrame, binaryData)
- 心跳机制:
// 服务端发送Ping spawn { while (true) { sleep(Duration.minute) websocket.writePingFrame([]) } } // 客户端响应Pong match (frame.frameType) { case PingWebFrame => websocket.writePongFrame(frame.payload) // ... }
- 流量控制:
websocket.setReadBufferSize(1024 * 1024) // 1MB缓冲区 websocket.setWriteBufferSize(512 * 1024) // 512KB缓冲区
性能优化建议
-
连接复用:
- HTTP客户端启用连接池
- WebSocket长连接避免频繁重建
-
异步处理:
server.distributor.register("/async", { ctx => spawn { processRequest(ctx) } })
-
压缩传输:
ClientBuilder() .enableCompression() .build()
-
负载测试:
- 使用仓颉的
std.benchmark
进行压力测试 - 监控内存和CPU使用情况
- 使用仓颉的
安全实践
HTTP安全
-
HTTPS支持:
ServerBuilder() .tlsConfig(TLSConfig.load("cert.pem", "key.pem")) .build()
-
安全头部:
ctx.responseBuilder .header("X-Content-Type-Options", "nosniff") .header("X-Frame-Options", "DENY")
-
输入验证:
func validateInput(input: String): Boolean { !input.contains("<script>") && input.length < 1000 }
WebSocket安全
-
Origin验证:
if (ctx.request.headers.getFirst("Origin") != "trusted.com") { ctx.responseBuilder.status(403).body("Forbidden") return }
-
消息大小限制:
websocket.setMaxFrameSize(1024 * 1024) // 限制1MB/帧
-
认证授权:
let token = ctx.request.headers.getFirst("Authorization") if (!validateToken(token)) { websocket.writeCloseFrame(status: 1008) return }
调试与问题排查
常见问题解决
-
连接超时:
- 检查防火墙设置
- 增加超时时间:
ClientBuilder() .connectTimeout(Duration.second * 10) .build()
-
协议不匹配:
- 确保客户端和服务端使用相同的WebSocket子协议
- 验证HTTP版本兼容性
-
内存泄漏:
- 使用仓颉内存分析工具检查
- 确保所有资源都被正确关闭
调试工具
-
日志记录:
Logger.global.level = LogLevel.DEBUG
-
网络抓包:
- 使用Wireshark分析原始流量
- 检查HTTP升级过程和WebSocket帧
-
单元测试:
test("WebSocket握手测试") { let mockCtx = createMockContext() let ws = WebSocket.upgradeFromServer(mockCtx) assert(ws != null) }
总结
仓颉语言提供了现代、全面的HTTP和WebSocket编程支持,主要优势包括:
- 简洁的API设计:通过构建器模式和高层抽象简化开发
- 协议完整性:全面支持HTTP/1.1、HTTP/2和WebSocket协议
- 性能优化:内置连接池、压缩等优化手段
- 安全内置:提供TLS、认证等安全功能
- 可扩展架构:支持中间件、过滤器等扩展点
掌握这些网络编程技术,开发者可以高效构建Web服务、实时通信系统等各类网络应用。建议从简单示例开始,逐步深入理解协议细节和高级特性,最终开发出高性能、高可靠的网络服务。