From ce5efae287b65cf99181e19ea6ccbabf136d786d Mon Sep 17 00:00:00 2001 From: wjqserver <114663932+WJQSERVER@users.noreply.github.com> Date: Tue, 10 Jun 2025 21:37:53 +0800 Subject: [PATCH] update --- context.go | 28 +++++++++++++++++++++++----- ecw.go | 2 +- engine.go | 26 ++++++++++++++------------ recovery.go | 2 +- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/context.go b/context.go index d9ac4a6..a15ae3c 100644 --- a/context.go +++ b/context.go @@ -2,6 +2,7 @@ package touka import ( "context" + "encoding/gob" "errors" "fmt" "html/template" @@ -195,16 +196,32 @@ func (c *Context) String(code int, format string, values ...interface{}) { func (c *Context) JSON(code int, obj interface{}) { c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8") c.Writer.WriteHeader(code) - // 实际 JSON 编码 + // JSON 编码 jsonBytes, err := json.Marshal(obj) if err != nil { c.AddError(fmt.Errorf("failed to marshal JSON: %w", err)) - c.String(http.StatusInternalServerError, "Internal Server Error: Failed to marshal JSON") + //c.String(http.StatusInternalServerError, "Internal Server Error: Failed to marshal JSON") + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to marshal JSON: %w", err)) return } c.Writer.Write(jsonBytes) } +// GOB 向响应写入GOB数据 +// 设置 Content-Type 为 application/octet-stream +func (c *Context) GOB(code int, obj interface{}) { + c.Writer.Header().Set("Content-Type", "application/octet-stream") // 设置合适的 Content-Type + c.Writer.WriteHeader(code) + // GOB 编码 + encoder := gob.NewEncoder(c.Writer) + if err := encoder.Encode(obj); err != nil { + c.AddError(fmt.Errorf("failed to encode GOB: %w", err)) + //c.String(http.StatusInternalServerError, "Internal Server Error: Failed to encode GOB") + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to encode GOB: %w", err)) + return + } +} + // HTML 渲染 HTML 模板 // 如果 Engine 配置了 HTMLRender,则使用它进行渲染 // 否则,会进行简单的字符串输出 @@ -219,7 +236,8 @@ func (c *Context) HTML(code int, name string, obj interface{}) { err := tpl.ExecuteTemplate(c.Writer, name, obj) if err != nil { c.AddError(fmt.Errorf("failed to render HTML template '%s': %w", name, err)) - c.String(http.StatusInternalServerError, "Internal Server Error: Failed to render HTML template") + //c.String(http.StatusInternalServerError, "Internal Server Error: Failed to render HTML template") + c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to render HTML template '%s': %w", name, err)) } return } @@ -468,9 +486,9 @@ func (c *Context) GetAllReqHeader() http.Header { } // 使用定义的errorHandle来处理error并结束当前handle -func (c *Context) ErrorUseHandle(code int) { +func (c *Context) ErrorUseHandle(code int, err error) { if c.engine != nil && c.engine.errorHandle.handler != nil { - c.engine.errorHandle.handler(c, code) + c.engine.errorHandle.handler(c, code, err) c.Abort() return } else { diff --git a/ecw.go b/ecw.go index e43db3a..67b5c7d 100644 --- a/ecw.go +++ b/ecw.go @@ -136,7 +136,7 @@ func (ecw *errorCapturingResponseWriter) processAfterFileServer() { ecw.ctx.Next() } else { // 调用用户自定义的 ErrorHandlerFunc, 由它负责完整的错误响应 - ecw.errorHandlerFunc(ecw.ctx, ecw.Status()) + ecw.errorHandlerFunc(ecw.ctx, ecw.Status(), errors.New("file server error")) ecw.ctx.Abort() } } diff --git a/engine.go b/engine.go index 337ebc6..da1d9ad 100644 --- a/engine.go +++ b/engine.go @@ -2,6 +2,7 @@ package touka import ( "context" + "errors" "log" "reflect" "runtime" @@ -70,10 +71,10 @@ type ErrorHandle struct { handler ErrorHandler } -type ErrorHandler func(c *Context, code int) +type ErrorHandler func(c *Context, code int, err error) // defaultErrorHandle 默认错误处理 -func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断开连接 +func defaultErrorHandle(c *Context, code int, err error) { // 检查客户端是否已断开连接 select { case <-c.Request.Context().Done(): @@ -86,6 +87,7 @@ func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断 c.JSON(code, H{ "code": code, "message": http.StatusText(code), + "error": err, }) c.Writer.Flush() c.Abort() @@ -95,17 +97,17 @@ func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断 // 默认errorhandle包装 避免竞争意外问题, 保证稳定性 func defaultErrorWarp(handler ErrorHandler) ErrorHandler { - return func(c *Context, code int) { + return func(c *Context, code int, err error) { select { case <-c.Request.Context().Done(): return default: if c.Writer.Written() { - log.Printf("errpage: response already started for status %d, skipping error page rendering", code) + log.Printf("errpage: response already started for status %d, skipping error page rendering, err: %v", code, err) return } } - handler(c, code) + handler(c, code, err) } } @@ -431,7 +433,7 @@ func unMatchFSHandle() HandlerFunc { c.Abort() return } else { - engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) return } } else { @@ -476,7 +478,7 @@ func MethodNotAllowed() HandlerFunc { value := treeIter.root.getValue(requestPath, nil, &tempSkippedNodes, false) // 只查找是否存在,不需要参数 if value.handlers != nil { // 使用定义的ErrorHandle处理 - engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) return } } @@ -487,7 +489,7 @@ func MethodNotAllowed() HandlerFunc { func NotFound() HandlerFunc { return func(c *Context) { engine := c.engine - engine.errorHandle.handler(c, http.StatusNotFound) + engine.errorHandle.handler(c, http.StatusNotFound, errors.New("not found")) return } } @@ -682,7 +684,7 @@ func (engine *Engine) Static(relativePath, rootPath string) { c.Next() } else { // 否则,返回 405 Method Not Allowed - engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) } return } @@ -746,7 +748,7 @@ func (group *RouterGroup) Static(relativePath, rootPath string) { c.Next() } else { // 否则,返回 405 Method Not Allowed - group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) } return } @@ -805,7 +807,7 @@ func (engine *Engine) StaticFile(relativePath, filePath string) { c.Next() } else { // 否则,返回 405 Method Not Allowed - engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) } return } @@ -861,7 +863,7 @@ func (group *RouterGroup) StaticFile(relativePath, filePath string) { c.Next() } else { // 否则,返回 405 Method Not Allowed - group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed) + group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed")) } return } diff --git a/recovery.go b/recovery.go index fc1e573..a50f54b 100644 --- a/recovery.go +++ b/recovery.go @@ -91,7 +91,7 @@ func defaultPanicHandler(c *Context, r interface{}) { // 尝试发送 500 Internal Server Error 响应 // 使用框架提供的统一错误处理器(如果可用) if c.engine != nil && c.engine.errorHandle.handler != nil { - c.engine.errorHandle.handler(c, http.StatusInternalServerError) + c.engine.errorHandle.handler(c, http.StatusInternalServerError, errors.New("Internal Panic Error")) } else { // 如果框架错误处理器不可用,提供一个备用的简单响应 // 返回英文错误信息