228 lines
6.6 KiB
V
228 lines
6.6 KiB
V
module hono
|
|
|
|
import net.http
|
|
import json
|
|
|
|
// 错误类型枚举
|
|
pub enum ErrorType {
|
|
bad_request = 400
|
|
unauthorized = 401
|
|
forbidden = 403
|
|
not_found = 404
|
|
method_not_allowed = 405
|
|
conflict = 409
|
|
payload_too_large = 413
|
|
unsupported_media_type = 415
|
|
unprocessable_entity = 422
|
|
internal_server_error = 500
|
|
not_implemented = 501
|
|
bad_gateway = 502
|
|
service_unavailable = 503
|
|
}
|
|
|
|
// 标准化错误响应结构
|
|
pub struct ErrorResponse {
|
|
pub:
|
|
error string
|
|
message string
|
|
code int
|
|
timestamp string
|
|
path string
|
|
details map[string]string
|
|
}
|
|
|
|
// 错误处理器接口
|
|
pub interface IErrorHandler {
|
|
handle_error(mut c Context, error_type ErrorType, message string, details map[string]string) http.Response
|
|
}
|
|
|
|
// 默认错误处理器
|
|
pub struct DefaultErrorHandler {}
|
|
|
|
// 实现错误处理器接口
|
|
pub fn (eh DefaultErrorHandler) handle_error(mut c Context, error_type ErrorType, message string, details map[string]string) http.Response {
|
|
error_response := ErrorResponse{
|
|
error: get_error_name(error_type)
|
|
message: message
|
|
code: int(error_type)
|
|
timestamp: get_current_timestamp()
|
|
path: c.path
|
|
details: details
|
|
}
|
|
|
|
c.status(int(error_type))
|
|
return c.json(json.encode(error_response))
|
|
}
|
|
|
|
// 获取错误名称
|
|
fn get_error_name(error_type ErrorType) string {
|
|
return match error_type {
|
|
.bad_request { 'Bad Request' }
|
|
.unauthorized { 'Unauthorized' }
|
|
.forbidden { 'Forbidden' }
|
|
.not_found { 'Not Found' }
|
|
.method_not_allowed { 'Method Not Allowed' }
|
|
.conflict { 'Conflict' }
|
|
.payload_too_large { 'Payload Too Large' }
|
|
.unsupported_media_type { 'Unsupported Media Type' }
|
|
.unprocessable_entity { 'Unprocessable Entity' }
|
|
.internal_server_error { 'Internal Server Error' }
|
|
.not_implemented { 'Not Implemented' }
|
|
.bad_gateway { 'Bad Gateway' }
|
|
.service_unavailable { 'Service Unavailable' }
|
|
}
|
|
}
|
|
|
|
// 获取当前时间戳
|
|
fn get_current_timestamp() string {
|
|
// 简化的时间戳实现
|
|
return '2025-12-26T00:00:00Z'
|
|
}
|
|
|
|
// Context 扩展方法 - 便捷的错误处理
|
|
pub fn (mut c Context) error_response(error_type ErrorType, message string) http.Response {
|
|
return c.error_response_with_details(error_type, message, map[string]string{})
|
|
}
|
|
|
|
pub fn (mut c Context) error_response_with_details(error_type ErrorType, message string, details map[string]string) http.Response {
|
|
handler := DefaultErrorHandler{}
|
|
return handler.handle_error(mut c, error_type, message, details)
|
|
}
|
|
|
|
// 常用错误处理快捷方法
|
|
pub fn (mut c Context) bad_request(message string) http.Response {
|
|
return c.error_response(.bad_request, message)
|
|
}
|
|
|
|
pub fn (mut c Context) unauthorized(message string) http.Response {
|
|
return c.error_response(.unauthorized, message)
|
|
}
|
|
|
|
pub fn (mut c Context) forbidden(message string) http.Response {
|
|
return c.error_response(.forbidden, message)
|
|
}
|
|
|
|
pub fn (mut c Context) not_found(message string) http.Response {
|
|
return c.error_response(.not_found, message)
|
|
}
|
|
|
|
pub fn (mut c Context) internal_error(message string) http.Response {
|
|
return c.error_response(.internal_server_error, message)
|
|
}
|
|
|
|
pub fn (mut c Context) validation_error(message string, field_errors map[string]string) http.Response {
|
|
return c.error_response_with_details(.unprocessable_entity, message, field_errors)
|
|
}
|
|
|
|
// 参数验证错误处理
|
|
pub fn (mut c Context) missing_parameter(param_name string) http.Response {
|
|
return c.bad_request('Missing required parameter: ${param_name}')
|
|
}
|
|
|
|
pub fn (mut c Context) invalid_parameter(param_name string, reason string) http.Response {
|
|
details := {
|
|
'parameter': param_name
|
|
'reason': reason
|
|
}
|
|
return c.error_response_with_details(.bad_request, 'Invalid parameter: ${param_name}', details)
|
|
}
|
|
|
|
// 资源相关错误处理
|
|
pub fn (mut c Context) resource_not_found(resource_type string, resource_id string) http.Response {
|
|
details := {
|
|
'resource_type': resource_type
|
|
'resource_id': resource_id
|
|
}
|
|
return c.error_response_with_details(.not_found, '${resource_type} not found', details)
|
|
}
|
|
|
|
pub fn (mut c Context) resource_conflict(resource_type string, reason string) http.Response {
|
|
details := {
|
|
'resource_type': resource_type
|
|
'reason': reason
|
|
}
|
|
return c.error_response_with_details(.conflict, 'Resource conflict: ${reason}', details)
|
|
}
|
|
|
|
// 文件操作错误处理
|
|
pub fn (mut c Context) file_operation_error(operation string, filename string, reason string) http.Response {
|
|
details := {
|
|
'operation': operation
|
|
'filename': filename
|
|
'reason': reason
|
|
}
|
|
return c.error_response_with_details(.internal_server_error, 'File operation failed: ${operation}', details)
|
|
}
|
|
|
|
// 数据库操作错误处理
|
|
pub fn (mut c Context) database_error(operation string, reason string) http.Response {
|
|
details := {
|
|
'operation': operation
|
|
'reason': reason
|
|
}
|
|
return c.error_response_with_details(.internal_server_error, 'Database operation failed', details)
|
|
}
|
|
|
|
// 验证结果处理
|
|
pub fn handle_validation_result[T](mut c Context, result !T, param_name string) !T {
|
|
return result or {
|
|
// 这里不能直接返回 http.Response,需要在调用处处理
|
|
return error('Validation failed for ${param_name}: ${err}')
|
|
}
|
|
}
|
|
|
|
// 全局错误处理中间件
|
|
pub fn error_handling_middleware() fn (mut Context, fn (mut Context) http.Response) http.Response {
|
|
return fn (mut c Context, next fn (mut Context) http.Response) http.Response {
|
|
// 捕获 panic 并转换为错误响应
|
|
// V语言目前不支持 try-catch,这里提供结构化的错误处理框架
|
|
response := next(mut c)
|
|
|
|
// 如果响应状态码是错误状态,确保响应格式一致
|
|
if c.status_code >= 400 {
|
|
// 如果响应体不是标准错误格式,转换为标准格式
|
|
if !response.body.contains('"error"') {
|
|
error_type := match c.status_code {
|
|
400 { ErrorType.bad_request }
|
|
401 { ErrorType.unauthorized }
|
|
403 { ErrorType.forbidden }
|
|
404 { ErrorType.not_found }
|
|
409 { ErrorType.conflict }
|
|
422 { ErrorType.unprocessable_entity }
|
|
500 { ErrorType.internal_server_error }
|
|
else { ErrorType.internal_server_error }
|
|
}
|
|
return c.error_response(error_type, response.body)
|
|
}
|
|
}
|
|
|
|
return response
|
|
}
|
|
}
|
|
|
|
// 错误日志记录
|
|
pub struct ErrorLogger {
|
|
mut:
|
|
enabled bool = true
|
|
}
|
|
|
|
pub fn (mut logger ErrorLogger) log_error(error_response ErrorResponse, request_info string) {
|
|
if !logger.enabled {
|
|
return
|
|
}
|
|
|
|
println('[ERROR] ${error_response.timestamp} - ${error_response.code} ${error_response.error}')
|
|
println(' Path: ${error_response.path}')
|
|
println(' Message: ${error_response.message}')
|
|
if error_response.details.len > 0 {
|
|
println(' Details: ${error_response.details}')
|
|
}
|
|
println(' Request: ${request_info}')
|
|
}
|
|
|
|
// 创建错误日志实例
|
|
pub fn new_error_logger() ErrorLogger {
|
|
return ErrorLogger{
|
|
enabled: true
|
|
}
|
|
} |