refc: Refactor project structure
This commit is contained in:
@@ -1,379 +1,213 @@
|
||||
# V-Hono
|
||||
# v-hono
|
||||
|
||||
一个用 V 语言编写的高性能 Web 框架,灵感来自 [Hono.js](https://hono.dev/)。
|
||||
A high-performance V language web framework inspired by [Hono.js](https://hono.dev/).
|
||||
|
||||
## 特性
|
||||
## Features
|
||||
|
||||
- 🚀 高性能路由系统(FastRouter + LRU 缓存 + 预编译正则)
|
||||
- 🎯 类似 Hono.js 的 Context API
|
||||
- 🔧 洋葱模型中间件支持
|
||||
- 📦 内置 LRU 缓存系统
|
||||
- 🛠️ 动态路由参数(`:param`)和通配符路由(`*`、`**`)
|
||||
- 🔄 支持所有 HTTP 方法(GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS)
|
||||
- 🏗️ 路由分组与子应用中间件继承
|
||||
- 📁 静态文件服务中间件
|
||||
- 🛡️ 内置安全防护(路径遍历攻击防护、点文件访问控制)
|
||||
- 💾 智能缓存支持(ETag、Last-Modified、Cache-Control)
|
||||
- 📤 大文件分片上传(断点续传、秒传、自动合并)
|
||||
- 🔐 用户认证系统(JWT、角色权限、菜单管理)
|
||||
- 📊 配置管理系统
|
||||
- 🗄️ SQLite 数据库集成
|
||||
- 🚀 **High Performance** - Hybrid routing with LRU cache for optimal speed
|
||||
- 🎯 **Simple API** - Clean and intuitive API design inspired by Hono.js
|
||||
- 🔧 **Middleware Support** - Flexible middleware system with onion model
|
||||
- 📁 **Static File Serving** - Built-in static file server with caching
|
||||
- 🔐 **Security** - Path validation and security utilities
|
||||
- 📤 **File Upload** - Chunked file upload support
|
||||
- 🗄️ **Database** - SQLite integration for data persistence
|
||||
- 🔑 **Authentication** - Built-in auth system with JWT-like tokens
|
||||
|
||||
## 性能测试
|
||||
## Installation
|
||||
|
||||
基于 100,000 次迭代的路由匹配性能测试:
|
||||
|
||||
| 框架 | 平均延迟 | 吞吐量 |
|
||||
|------|---------|--------|
|
||||
| v-hono | 5,621 ns/op | **177,904 ops/sec** |
|
||||
| 简单路由器 | 9,265 ns/op | 107,933 ops/sec |
|
||||
|
||||
v-hono 在动态路由场景下优势明显,得益于 LRU 缓存和预编译正则表达式。
|
||||
|
||||
## 安装
|
||||
### From VPM
|
||||
|
||||
```bash
|
||||
git clone https://github.com/meiseayoung/v-hono.git
|
||||
cd v-hono
|
||||
v run example.v
|
||||
v install your-github-username.hono
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
### From GitHub
|
||||
|
||||
```bash
|
||||
v install --git https://github.com/your-username/v-hono
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
Clone the repository and the module will be available for import:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/v-hono.git
|
||||
cd v-hono
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```v
|
||||
import hono
|
||||
import net.http
|
||||
import hono
|
||||
|
||||
fn main() {
|
||||
mut app := hono.Hono.new()
|
||||
|
||||
// 基本路由
|
||||
|
||||
app.get('/', fn (mut c hono.Context) http.Response {
|
||||
return c.html('<h1>Hello V-Hono!</h1>')
|
||||
return c.text('Hello, World!')
|
||||
})
|
||||
|
||||
// 动态路由
|
||||
|
||||
app.get('/json', fn (mut c hono.Context) http.Response {
|
||||
return c.json('{"message": "Hello, JSON!"}')
|
||||
})
|
||||
|
||||
app.get('/users/:id', fn (mut c hono.Context) http.Response {
|
||||
user_id := c.params['id']
|
||||
return c.json('{"id": "${user_id}"}')
|
||||
user_id := c.params['id'] or { 'unknown' }
|
||||
return c.json('{"user_id": "${user_id}"}')
|
||||
})
|
||||
|
||||
// 中间件
|
||||
app.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response {
|
||||
println('[LOG] ${c.path}')
|
||||
return next(mut c)
|
||||
})
|
||||
|
||||
|
||||
app.listen(':3000')
|
||||
}
|
||||
```
|
||||
|
||||
## 路由分组
|
||||
|
||||
支持子应用路由分组,中间件自动继承:
|
||||
## Middleware
|
||||
|
||||
```v
|
||||
// 创建子应用
|
||||
mut api := hono.Hono.new()
|
||||
import net.http
|
||||
import time
|
||||
import hono
|
||||
|
||||
// 子应用中间件(只对 /api/* 生效)
|
||||
api.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response {
|
||||
c.headers['X-API-Version'] = '1.0'
|
||||
return next(mut c)
|
||||
})
|
||||
fn main() {
|
||||
mut app := hono.Hono.new()
|
||||
|
||||
api.get('/users', fn (mut c hono.Context) http.Response {
|
||||
return c.json('{"users": []}')
|
||||
})
|
||||
// Logger middleware
|
||||
app.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response {
|
||||
start := time.now()
|
||||
response := next(mut c)
|
||||
duration := time.since(start)
|
||||
println('[${c.req.method}] ${c.path} - ${duration}')
|
||||
return response
|
||||
})
|
||||
|
||||
// 挂载到主应用
|
||||
app.route('/api', mut api)
|
||||
```
|
||||
app.get('/', fn (mut c hono.Context) http.Response {
|
||||
return c.text('Hello with middleware!')
|
||||
})
|
||||
|
||||
## all() 方法
|
||||
|
||||
一次性为所有 HTTP 方法注册处理器:
|
||||
|
||||
```v
|
||||
app.all('/echo', fn (mut c hono.Context) http.Response {
|
||||
return c.json('{"method": "${c.req.method}"}')
|
||||
})
|
||||
```
|
||||
|
||||
## 自定义错误处理
|
||||
|
||||
```v
|
||||
// 自定义 404 处理器
|
||||
app.not_found(fn (mut c hono.Context) http.Response {
|
||||
c.status(404)
|
||||
return c.json('{"error": "Not Found", "path": "${c.path}"}')
|
||||
})
|
||||
|
||||
// 自定义错误处理器
|
||||
app.on_error(fn (error_msg string, status_code int, mut c hono.Context) http.Response {
|
||||
c.status(status_code)
|
||||
return c.json('{"error": "${error_msg}"}')
|
||||
})
|
||||
```
|
||||
|
||||
## 静态文件服务
|
||||
|
||||
```v
|
||||
// 默认配置(./public 目录)
|
||||
app.use(hono.serve_static_default())
|
||||
|
||||
// 指定路径前缀和根目录
|
||||
app.use(hono.serve_static_path('/assets', './static'))
|
||||
|
||||
// 自定义配置
|
||||
options := hono.StaticOptions{
|
||||
root: './public'
|
||||
path: '/static'
|
||||
index: 'index.html'
|
||||
etag: true
|
||||
last_modified: true
|
||||
max_age: 3600
|
||||
app.listen(':3000')
|
||||
}
|
||||
app.use(hono.serve_static(options))
|
||||
```
|
||||
|
||||
## 响应方法
|
||||
## Route Grouping
|
||||
|
||||
```v
|
||||
// JSON 响应
|
||||
return c.json('{"message": "Hello"}')
|
||||
import net.http
|
||||
import hono
|
||||
|
||||
// 文本响应
|
||||
return c.text('Hello World')
|
||||
fn main() {
|
||||
mut app := hono.Hono.new()
|
||||
|
||||
// HTML 响应
|
||||
return c.html('<h1>Hello</h1>')
|
||||
|
||||
// 文件响应
|
||||
return c.file('path/to/file.pdf')
|
||||
|
||||
// 设置状态码
|
||||
c.status(201)
|
||||
return c.json('{"created": true}')
|
||||
|
||||
// 错误响应
|
||||
return c.not_found('Resource not found')
|
||||
return c.unauthorized('Token required')
|
||||
return c.forbidden('Access denied')
|
||||
```
|
||||
|
||||
|
||||
## 大文件分片上传
|
||||
|
||||
支持大文件分片上传、断点续传、秒传功能:
|
||||
|
||||
```v
|
||||
mut upload_manager := hono.new_chunk_upload_manager(hono.ChunkUploadConfig{
|
||||
chunk_size: 1024 * 1024 // 1MB 分片
|
||||
max_file_size: 1024 * 1024 * 1024 // 最大 1GB
|
||||
temp_dir: './uploads/chunks'
|
||||
upload_dir: './uploads/files'
|
||||
})
|
||||
|
||||
// 分片上传接口
|
||||
app.post('/upload/chunk', fn [mut upload_manager] (mut c hono.Context) http.Response {
|
||||
return upload_manager.handle_chunk_upload(mut c)
|
||||
})
|
||||
|
||||
// 上传状态查询
|
||||
app.get('/upload/status', fn [mut upload_manager] (mut c hono.Context) http.Response {
|
||||
return upload_manager.get_upload_status(mut c)
|
||||
})
|
||||
```
|
||||
|
||||
### 前端示例
|
||||
|
||||
```javascript
|
||||
// 请求池管理(控制并发)
|
||||
const requestPool = new RequestPool(6);
|
||||
|
||||
// 分片上传
|
||||
async function uploadChunk(file, chunk, { fileHash, chunkIndex, chunkHash }) {
|
||||
const form = new FormData();
|
||||
form.append('file_hash', fileHash);
|
||||
form.append('chunk_index', chunkIndex);
|
||||
form.append('chunk', chunk);
|
||||
// Create API sub-application
|
||||
mut api := hono.Hono.new()
|
||||
|
||||
const response = await fetch('/upload/chunk', { method: 'POST', body: form });
|
||||
return response.json();
|
||||
api.get('/users', fn (mut c hono.Context) http.Response {
|
||||
return c.json('[{"id": 1, "name": "Alice"}]')
|
||||
})
|
||||
|
||||
api.get('/users/:id', fn (mut c hono.Context) http.Response {
|
||||
user_id := c.params['id'] or { 'unknown' }
|
||||
return c.json('{"id": ${user_id}}')
|
||||
})
|
||||
|
||||
// Mount API routes under /api prefix
|
||||
app.route('/api', mut api)
|
||||
|
||||
app.listen(':3000')
|
||||
}
|
||||
```
|
||||
|
||||
详细文档:[README_CHUNK_UPLOAD.md](README_CHUNK_UPLOAD.md)
|
||||
|
||||
## 用户认证系统
|
||||
|
||||
内置完整的用户认证和权限管理:
|
||||
## Static File Serving
|
||||
|
||||
```v
|
||||
// 初始化认证管理器
|
||||
mut db := hono.new_database_manager('./auth.db')
|
||||
mut auth := hono.new_auth_manager(db)
|
||||
auth.init_tables()!
|
||||
import net.http
|
||||
import hono
|
||||
|
||||
// 创建用户
|
||||
user := auth.create_user('admin', 'admin@example.com', 'password', .admin)!
|
||||
fn main() {
|
||||
mut app := hono.Hono.new()
|
||||
|
||||
// 用户登录
|
||||
session := auth.login('admin', 'password')!
|
||||
// Serve static files from ./public directory
|
||||
app.use(hono.serve_static(hono.StaticOptions{
|
||||
root: './public'
|
||||
path: '/static'
|
||||
}))
|
||||
|
||||
// 验证令牌
|
||||
user := auth.verify_token(session.token)!
|
||||
|
||||
// 权限检查
|
||||
if auth.check_permission(user, 'write') {
|
||||
// 允许操作
|
||||
app.listen(':3000')
|
||||
}
|
||||
```
|
||||
|
||||
### 用户角色
|
||||
## API Reference
|
||||
|
||||
- `admin` - 管理员(所有权限)
|
||||
- `manager` - 管理者(read、write、manage)
|
||||
- `user` - 普通用户(read、write)
|
||||
- `guest` - 访客(read)
|
||||
### Hono
|
||||
|
||||
详细文档:[README_AUTH_SYSTEM.md](README_AUTH_SYSTEM.md)
|
||||
|
||||
## 配置管理
|
||||
|
||||
```v
|
||||
// 加载配置
|
||||
config := hono.load_config('config.json')!
|
||||
|
||||
// 获取配置值
|
||||
db_path := config.get_string('database.path')
|
||||
port := config.get_int('server.port')
|
||||
debug := config.get_bool('debug')
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
v-hono/
|
||||
├── hono/ # 核心模块
|
||||
│ ├── app.v # 主应用
|
||||
│ ├── fast_router.v # 快速路由器
|
||||
│ ├── cache.v # LRU 缓存
|
||||
│ ├── auth.v # 认证系统
|
||||
│ ├── database.v # 数据库管理
|
||||
│ ├── upload.v # 分片上传
|
||||
│ ├── static.v # 静态文件服务
|
||||
│ ├── response.v # 响应方法
|
||||
│ ├── error_handler.v # 错误处理
|
||||
│ ├── security.v # 安全模块
|
||||
│ └── ...
|
||||
├── public/ # 静态文件目录
|
||||
├── uploads/ # 上传文件目录
|
||||
├── example.v # 完整示例
|
||||
├── route_grouping_example_v2.v # 路由分组示例
|
||||
└── benchmark_vweb_vs_hono.v # 性能测试
|
||||
```
|
||||
|
||||
## API 参考
|
||||
- `Hono.new()` - Create a new Hono application
|
||||
- `app.get(path, handler)` - Register GET route
|
||||
- `app.post(path, handler)` - Register POST route
|
||||
- `app.put(path, handler)` - Register PUT route
|
||||
- `app.delete(path, handler)` - Register DELETE route
|
||||
- `app.patch(path, handler)` - Register PATCH route
|
||||
- `app.all(path, handler)` - Register route for all methods
|
||||
- `app.use(middleware)` - Add middleware
|
||||
- `app.route(prefix, subapp)` - Mount sub-application
|
||||
- `app.listen(port)` - Start server
|
||||
|
||||
### Context
|
||||
|
||||
```v
|
||||
pub struct Context {
|
||||
pub:
|
||||
req http.Request // 原始请求
|
||||
params map[string]string // 路径参数
|
||||
query map[string]string // 查询参数
|
||||
url string // 请求 URL
|
||||
path string // 请求路径
|
||||
pub mut:
|
||||
status_code int = 200 // 响应状态码
|
||||
headers map[string]string // 响应头
|
||||
body string // 请求体
|
||||
}
|
||||
- `c.text(data)` - Return text response
|
||||
- `c.json(data)` - Return JSON response
|
||||
- `c.html(data)` - Return HTML response
|
||||
- `c.file(path)` - Return file response
|
||||
- `c.status(code)` - Set response status code
|
||||
- `c.params` - Route parameters
|
||||
- `c.query` - Query parameters
|
||||
- `c.body` - Request body
|
||||
- `c.headers` - Response headers
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
v-hono/
|
||||
├── app.v # Main application and routing
|
||||
├── router.v # Hybrid router implementation
|
||||
├── fast_router.v # Fast router with precompiled regex
|
||||
├── trie_router.v # Trie-based router
|
||||
├── cache.v # LRU cache implementation
|
||||
├── request.v # Request context
|
||||
├── response.v # Response utilities
|
||||
├── static.v # Static file serving
|
||||
├── security.v # Security utilities
|
||||
├── config.v # Configuration management
|
||||
├── logger.v # Logging system
|
||||
├── multipart.v # Multipart form parsing
|
||||
├── json_parser.v # JSON parsing utilities
|
||||
├── upload.v # File upload handling
|
||||
├── database.v # Database integration
|
||||
├── auth.v # Authentication system
|
||||
├── auth_routes.v # Auth route handlers
|
||||
├── error_handler.v # Error handling
|
||||
├── v.mod # Module definition
|
||||
├── README.md # Documentation
|
||||
├── examples/ # Example applications
|
||||
├── tests/ # Test files
|
||||
└── docs/ # Additional documentation
|
||||
```
|
||||
|
||||
### 路由方法
|
||||
## Examples
|
||||
|
||||
```v
|
||||
app.get(path, handler) // GET 请求
|
||||
app.post(path, handler) // POST 请求
|
||||
app.put(path, handler) // PUT 请求
|
||||
app.delete(path, handler) // DELETE 请求
|
||||
app.patch(path, handler) // PATCH 请求
|
||||
app.head(path, handler) // HEAD 请求
|
||||
app.options(path, handler) // OPTIONS 请求
|
||||
app.all(path, handler) // 所有方法
|
||||
```
|
||||
See the `examples/` directory for more examples:
|
||||
|
||||
### 动态路由
|
||||
- `examples/basic/` - Basic usage
|
||||
- `examples/middleware/` - Middleware usage
|
||||
- `examples/route_grouping/` - Route grouping
|
||||
|
||||
```v
|
||||
// 单参数
|
||||
app.get('/users/:id', handler)
|
||||
## Publishing to VPM
|
||||
|
||||
// 多参数
|
||||
app.get('/users/:id/posts/:post_id', handler)
|
||||
1. Create a GitHub repository for your project
|
||||
2. Push your code to GitHub
|
||||
3. Go to https://vpm.vlang.io/new
|
||||
4. Login with your GitHub account
|
||||
5. Submit your package
|
||||
|
||||
// 通配符
|
||||
app.get('/files/*path', handler)
|
||||
```
|
||||
|
||||
### 中间件
|
||||
|
||||
```v
|
||||
// 全局中间件
|
||||
app.use(middleware)
|
||||
|
||||
// 子应用中间件(只对特定前缀生效)
|
||||
mut api := hono.Hono.new()
|
||||
api.use(api_middleware)
|
||||
app.route('/api', mut api)
|
||||
```
|
||||
|
||||
## 运行示例
|
||||
|
||||
```bash
|
||||
# 完整示例
|
||||
v run example.v
|
||||
|
||||
# 路由分组示例
|
||||
v run route_grouping_example_v2.v
|
||||
|
||||
# 性能测试
|
||||
v run benchmark_vweb_vs_hono.v
|
||||
```
|
||||
|
||||
## 测试命令
|
||||
|
||||
```bash
|
||||
# 基本测试
|
||||
curl http://localhost:8080/
|
||||
curl http://localhost:8080/api/health
|
||||
curl http://localhost:8080/users/123
|
||||
|
||||
# POST 请求
|
||||
curl -X POST http://localhost:8080/api/users -d '{"name":"John"}'
|
||||
|
||||
# 静态文件
|
||||
curl http://localhost:8080/test.txt
|
||||
|
||||
# 分片上传
|
||||
curl -X POST http://localhost:8080/upload/chunk \
|
||||
-F "file_hash=abc123" \
|
||||
-F "chunk_index=0" \
|
||||
-F "chunk=@file.part"
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [分片上传系统](README_CHUNK_UPLOAD.md)
|
||||
- [请求池系统](README_REQUEST_POOL.md)
|
||||
- [认证系统](README_AUTH_SYSTEM.md)
|
||||
- [数据库模块](README_DATABASE.md)
|
||||
- [性能测试](README_BENCHMARK.md)
|
||||
|
||||
## 许可证
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
Reference in New Issue
Block a user