This commit is contained in:
wjqserver 2025-06-10 21:37:53 +08:00
parent e6b54eedbf
commit ce5efae287
4 changed files with 39 additions and 19 deletions

View file

@ -2,6 +2,7 @@ package touka
import ( import (
"context" "context"
"encoding/gob"
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
@ -195,16 +196,32 @@ func (c *Context) String(code int, format string, values ...interface{}) {
func (c *Context) JSON(code int, obj interface{}) { func (c *Context) JSON(code int, obj interface{}) {
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8") c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
c.Writer.WriteHeader(code) c.Writer.WriteHeader(code)
// 实际 JSON 编码 // JSON 编码
jsonBytes, err := json.Marshal(obj) jsonBytes, err := json.Marshal(obj)
if err != nil { if err != nil {
c.AddError(fmt.Errorf("failed to marshal JSON: %w", err)) 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 return
} }
c.Writer.Write(jsonBytes) 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 模板 // HTML 渲染 HTML 模板
// 如果 Engine 配置了 HTMLRender则使用它进行渲染 // 如果 Engine 配置了 HTMLRender则使用它进行渲染
// 否则,会进行简单的字符串输出 // 否则,会进行简单的字符串输出
@ -219,7 +236,8 @@ func (c *Context) HTML(code int, name string, obj interface{}) {
err := tpl.ExecuteTemplate(c.Writer, name, obj) err := tpl.ExecuteTemplate(c.Writer, name, obj)
if err != nil { if err != nil {
c.AddError(fmt.Errorf("failed to render HTML template '%s': %w", name, err)) 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 return
} }
@ -468,9 +486,9 @@ func (c *Context) GetAllReqHeader() http.Header {
} }
// 使用定义的errorHandle来处理error并结束当前handle // 使用定义的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 { if c.engine != nil && c.engine.errorHandle.handler != nil {
c.engine.errorHandle.handler(c, code) c.engine.errorHandle.handler(c, code, err)
c.Abort() c.Abort()
return return
} else { } else {

2
ecw.go
View file

@ -136,7 +136,7 @@ func (ecw *errorCapturingResponseWriter) processAfterFileServer() {
ecw.ctx.Next() ecw.ctx.Next()
} else { } else {
// 调用用户自定义的 ErrorHandlerFunc, 由它负责完整的错误响应 // 调用用户自定义的 ErrorHandlerFunc, 由它负责完整的错误响应
ecw.errorHandlerFunc(ecw.ctx, ecw.Status()) ecw.errorHandlerFunc(ecw.ctx, ecw.Status(), errors.New("file server error"))
ecw.ctx.Abort() ecw.ctx.Abort()
} }
} }

View file

@ -2,6 +2,7 @@ package touka
import ( import (
"context" "context"
"errors"
"log" "log"
"reflect" "reflect"
"runtime" "runtime"
@ -70,10 +71,10 @@ type ErrorHandle struct {
handler ErrorHandler handler ErrorHandler
} }
type ErrorHandler func(c *Context, code int) type ErrorHandler func(c *Context, code int, err error)
// defaultErrorHandle 默认错误处理 // defaultErrorHandle 默认错误处理
func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断开连接 func defaultErrorHandle(c *Context, code int, err error) { // 检查客户端是否已断开连接
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -86,6 +87,7 @@ func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断
c.JSON(code, H{ c.JSON(code, H{
"code": code, "code": code,
"message": http.StatusText(code), "message": http.StatusText(code),
"error": err,
}) })
c.Writer.Flush() c.Writer.Flush()
c.Abort() c.Abort()
@ -95,17 +97,17 @@ func defaultErrorHandle(c *Context, code int) { // 检查客户端是否已断
// 默认errorhandle包装 避免竞争意外问题, 保证稳定性 // 默认errorhandle包装 避免竞争意外问题, 保证稳定性
func defaultErrorWarp(handler ErrorHandler) ErrorHandler { func defaultErrorWarp(handler ErrorHandler) ErrorHandler {
return func(c *Context, code int) { return func(c *Context, code int, err error) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
return return
default: default:
if c.Writer.Written() { 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 return
} }
} }
handler(c, code) handler(c, code, err)
} }
} }
@ -431,7 +433,7 @@ func unMatchFSHandle() HandlerFunc {
c.Abort() c.Abort()
return return
} else { } else {
engine.errorHandle.handler(c, http.StatusMethodNotAllowed) engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
return return
} }
} else { } else {
@ -476,7 +478,7 @@ func MethodNotAllowed() HandlerFunc {
value := treeIter.root.getValue(requestPath, nil, &tempSkippedNodes, false) // 只查找是否存在,不需要参数 value := treeIter.root.getValue(requestPath, nil, &tempSkippedNodes, false) // 只查找是否存在,不需要参数
if value.handlers != nil { if value.handlers != nil {
// 使用定义的ErrorHandle处理 // 使用定义的ErrorHandle处理
engine.errorHandle.handler(c, http.StatusMethodNotAllowed) engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
return return
} }
} }
@ -487,7 +489,7 @@ func MethodNotAllowed() HandlerFunc {
func NotFound() HandlerFunc { func NotFound() HandlerFunc {
return func(c *Context) { return func(c *Context) {
engine := c.engine engine := c.engine
engine.errorHandle.handler(c, http.StatusNotFound) engine.errorHandle.handler(c, http.StatusNotFound, errors.New("not found"))
return return
} }
} }
@ -682,7 +684,7 @@ func (engine *Engine) Static(relativePath, rootPath string) {
c.Next() c.Next()
} else { } else {
// 否则,返回 405 Method Not Allowed // 否则,返回 405 Method Not Allowed
engine.errorHandle.handler(c, http.StatusMethodNotAllowed) engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
} }
return return
} }
@ -746,7 +748,7 @@ func (group *RouterGroup) Static(relativePath, rootPath string) {
c.Next() c.Next()
} else { } else {
// 否则,返回 405 Method Not Allowed // 否则,返回 405 Method Not Allowed
group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed) group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
} }
return return
} }
@ -805,7 +807,7 @@ func (engine *Engine) StaticFile(relativePath, filePath string) {
c.Next() c.Next()
} else { } else {
// 否则,返回 405 Method Not Allowed // 否则,返回 405 Method Not Allowed
engine.errorHandle.handler(c, http.StatusMethodNotAllowed) engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
} }
return return
} }
@ -861,7 +863,7 @@ func (group *RouterGroup) StaticFile(relativePath, filePath string) {
c.Next() c.Next()
} else { } else {
// 否则,返回 405 Method Not Allowed // 否则,返回 405 Method Not Allowed
group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed) group.engine.errorHandle.handler(c, http.StatusMethodNotAllowed, errors.New("method not allowed"))
} }
return return
} }

View file

@ -91,7 +91,7 @@ func defaultPanicHandler(c *Context, r interface{}) {
// 尝试发送 500 Internal Server Error 响应 // 尝试发送 500 Internal Server Error 响应
// 使用框架提供的统一错误处理器(如果可用) // 使用框架提供的统一错误处理器(如果可用)
if c.engine != nil && c.engine.errorHandle.handler != nil { 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 { } else {
// 如果框架错误处理器不可用,提供一个备用的简单响应 // 如果框架错误处理器不可用,提供一个备用的简单响应
// 返回英文错误信息 // 返回英文错误信息