Files
v-hono/hono/README.MD
T

289 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Trie 路由树(高性能路由)
### 简介
Trie 路由树是一种高性能的路由匹配结构,广泛应用于现代 Web 框架。相比传统的正则遍历路由,Trie 路由树在大规模路由和高并发场景下具有更高的查找效率。
### 特性
- 支持静态路由、命名参数(如 `/user/:id`)、通配符(如 `/static/*filepath`)
- 支持正则路由(如 `/user/(?P<id>[^/]+)`),正则路由单独分流
- 路由树根节点按 HTTP 方法(GET/POST/PUT/DELETE)分流,进一步提升查找效率
- 内置 LRU 路由缓存,热点路由命中极快
- 性能测试显示 Trie 路由树在大规模动态路由下性能优于传统正则遍历
### 用法
注册路由时,框架会自动将路由注册到 Trie 路由树和 HybridRouter:
```v
app.get('/api/users/:id', fn (req hono.Request) http.Response {
return hono.Response.json('{"user_id": "${req.param["id"]}"}')
})
```
### 性能优势
- 静态路由、参数路由、通配符路由查找均为 O(n)(n为路径层级),极快
- 路由缓存命中时,查找仅需一次 map 查询,QPS 可达 20~30 万
- 支持上千条动态路由、百万级请求高并发场景
### 缓存说明
- Trie 路由树内置 LRU 缓存(默认容量1000),缓存 key 为 `method:path`,value 为 `RouteMatch`
- 命中缓存时性能极高,未命中时自动查找并写入缓存
- 可根据实际需求调整缓存容量
### 与 HybridRouter 对比
- HybridRouter 采用静态路由 map + 动态正则遍历,适合路由数量较少或兼容性需求高的场景
- TrieRouter 适合大规模路由、高并发、极致性能场景
- 两者可并存,便于灵活切换和对比测试
---
# 静态文件服务中间件
## 概述
为 V-Hono 框架添加了类似 Hono.js 的 `serveStatic` 中间件,提供高效、安全的静态文件服务功能。
## 实现文件
### 核心实现
- `hono/static.v` - 静态文件服务中间件的主要实现
### 示例文件
- `example.v` - 包含静态文件服务的完整示例
### 测试文件
- `public/index.html` - 默认索引文件
- `public/test.txt` - 测试文本文件
- `static/style.css` - 测试CSS文件
- `static/app.js` - 测试JavaScript文件
- `uploads/sample.json` - 测试JSON文件
## 核心功能
### 1. 静态文件服务中间件 (`serve_static`)
```v
pub fn serve_static(options StaticOptions) fn (mut Context, fn (mut Context) http.Response) http.Response
```
主要特性:
- 路径匹配和文件映射
- 安全检查(路径遍历攻击防护)
- 点文件访问控制
- 自动索引文件支持
- 智能错误处理
### 2. 配置选项 (`StaticOptions`)
```v
pub struct StaticOptions {
pub:
root string = './public' // 静态文件根目录
path string = '/' // URL路径前缀
index string = 'index.html' // 默认索引文件
dotfiles bool = false // 是否允许访问以.开头的文件
etag bool = true // 是否启用ETag
last_modified bool = true // 是否启用Last-Modified
max_age int = 0 // 缓存时间(秒)
headers map[string]string // 自定义响应头
}
```
### 3. 便捷函数
- `serve_static_default()` - 使用默认配置
- `serve_static_root(root string)` - 指定根目录
- `serve_static_path(path string, root string)` - 指定路径前缀和根目录
## 安全特性
### 路径遍历攻击防护
```v
fn is_safe_path(path string) bool {
// 检查是否包含 .. 或绝对路径
if path.contains('..') || path.starts_with('/') || path.starts_with('\\') {
return false
}
// 检查是否包含危险字符
dangerous_chars := ['<', '>', ':', '"', '|', '?', '*']
for char in dangerous_chars {
if path.contains(char) {
return false
}
}
return true
}
```
### 点文件访问控制
默认情况下阻止访问以 `.` 开头的文件,可通过 `dotfiles: true` 启用。
## 性能特性
### ETag 支持
```v
fn generate_etag(content string, mod_time i64) string {
return '"${content.len}-${mod_time}"'
}
```
### 缓存控制
```v
if options.max_age > 0 {
c.headers['Cache-Control'] = 'public, max-age=${options.max_age}'
} else {
c.headers['Cache-Control'] = 'no-cache'
}
```
### Content-Type 检测
支持30+种文件类型的自动Content-Type检测:
```v
fn get_content_type(file_path string) string {
ext := os.file_ext(file_path).to_lower()
match ext {
'.html', '.htm' { return 'text/html; charset=utf-8' }
'.css' { return 'text/css; charset=utf-8' }
'.js' { return 'application/javascript; charset=utf-8' }
'.json' { return 'application/json; charset=utf-8' }
// ... 更多类型
else { return 'application/octet-stream' }
}
}
```
## 使用示例
### 基本用法
```v
import hono
mut app := hono.Hono.new()
// 使用默认配置
app.use(hono.serve_static_default())
app.listen(':8080')
```
### 多目录配置
```v
// 默认静态文件
app.use(hono.serve_static_default())
// 资源文件
app.use(hono.serve_static_path('/assets', './static'))
// 上传文件
app.use(hono.serve_static_path('/uploads', './uploads'))
```
### 自定义配置
```v
options := hono.StaticOptions{
root: './public'
path: '/static'
index: 'index.html'
dotfiles: false
etag: true
last_modified: true
max_age: 3600
headers: {
'X-Served-By': 'V-Hono'
}
}
app.use(hono.serve_static(options))
```
## 与 Hono.js 的对比
| 特性 | V-Hono | Hono.js |
|------|--------|---------|
| 路径遍历防护 | ✅ | ✅ |
| 点文件控制 | ✅ | ✅ |
| ETag 支持 | ✅ | ✅ |
| Last-Modified | ✅ | ✅ |
| 缓存控制 | ✅ | ✅ |
| 自定义头部 | ✅ | ✅ |
| 自动索引文件 | ✅ | ✅ |
| Content-Type 检测 | ✅ | ✅ |
| 多目录支持 | ✅ | ✅ |
## 测试和验证
### 运行测试
```bash
# 完整示例
v run example.v
```
### 测试用例
1. **基本文件服务**
- 访问 `public/test.txt` → `/test.txt`
- 访问 `static/style.css` → `/assets/style.css`
2. **索引文件**
- 访问目录 `/` → 提供 `public/index.html`
3. **安全测试**
- 尝试路径遍历攻击 → 返回 403 Forbidden
- 尝试访问点文件 → 返回 403 Forbidden
4. **缓存测试**
- 检查 ETag 头
- 检查 Last-Modified 头
- 检查 Cache-Control 头
5. **Content-Type 测试**
- 验证不同文件类型的正确 Content-Type
## 性能考虑
### 优化点
1. **文件读取**: 使用 V 语言的 `os.read_file()` 进行高效文件读取
2. **路径检查**: 快速的安全路径验证
3. **头部生成**: 高效的响应头构建
4. **缓存策略**: 可配置的缓存控制
### 内存使用
- 文件内容一次性读取到内存
- 适合中小型文件
- 大文件建议使用专门的CDN服务
## 未来改进
### 可能的增强
1. **流式文件服务**: 支持大文件的流式传输
2. **压缩支持**: 自动Gzip压缩
3. **范围请求**: 支持HTTP Range请求
4. **文件监控**: 文件变化时自动刷新缓存
5. **性能监控**: 添加性能指标收集
### 扩展性
当前实现具有良好的扩展性,可以轻松添加:
- 新的文件类型支持
- 自定义安全检查
- 更多的缓存策略
- 文件预处理功能
## 总结
成功为 V-Hono 框架添加了功能完整、安全可靠的静态文件服务中间件,提供了与 Hono.js 相当的体验,同时充分利用了 V 语言的特性。该实现具有良好的安全性、性能和易用性,可以满足大多数Web应用的静态文件服务需求。