mirror of
https://github.com/infinite-iroha/touka.git
synced 2026-06-13 15:47:38 +08:00
feat(render): add Buf variants for JSON/GOB/WANF/HTML
Add buffered rendering methods that encode to a buffer first, then write the response. This allows returning a proper 500 status code if encoding fails, unlike the streaming variants which must write the status code before encoding (an inherent HTTP constraint). New methods: - JSONBuf(code int, obj any) - GOBBuf(code int, obj any) - WANFBuf(code int, obj any) - HTMLBuf(code int, name string, obj any) Trade-off: one extra memory allocation per call in exchange for correct error status codes on encoding failure.
This commit is contained in:
parent
559aefeb85
commit
7e15181c0b
1 changed files with 65 additions and 0 deletions
65
context.go
65
context.go
|
|
@ -417,6 +417,21 @@ func (c *Context) JSON(code int, obj any) {
|
|||
}
|
||||
}
|
||||
|
||||
// JSONBuf 先将 JSON 编码到 buffer, 成功后再写入状态码和响应体.
|
||||
// 与 JSON 相比, 编码失败时可以正确返回 500 状态码, 代价是多一次内存分配.
|
||||
func (c *Context) JSONBuf(code int, obj any) {
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
c.AddError(fmt.Errorf("failed to marshal JSON: %w", err))
|
||||
c.Errorf("failed to marshal JSON: %s", err)
|
||||
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to marshal JSON: %w", err))
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Writer.Write(data)
|
||||
}
|
||||
|
||||
// GOB 向响应写入GOB数据
|
||||
// 设置 Content-Type 为 application/octet-stream
|
||||
func (c *Context) GOB(code int, obj any) {
|
||||
|
|
@ -431,6 +446,20 @@ func (c *Context) GOB(code int, obj any) {
|
|||
}
|
||||
}
|
||||
|
||||
// GOBBuf 先将 GOB 编码到 buffer, 成功后再写入状态码和响应体.
|
||||
func (c *Context) GOBBuf(code int, obj any) {
|
||||
var buf bytes.Buffer
|
||||
encoder := gob.NewEncoder(&buf)
|
||||
if err := encoder.Encode(obj); err != nil {
|
||||
c.AddError(fmt.Errorf("failed to encode GOB: %w", err))
|
||||
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to encode GOB: %w", err))
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Set("Content-Type", "application/octet-stream")
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Writer.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
// WANF向响应写入WANF数据
|
||||
// 设置 application/vnd.wjqserver.wanf; charset=utf-8
|
||||
func (c *Context) WANF(code int, obj any) {
|
||||
|
|
@ -445,6 +474,19 @@ func (c *Context) WANF(code int, obj any) {
|
|||
}
|
||||
}
|
||||
|
||||
// WANFBuf 先将 WANF 编码到 buffer, 成功后再写入状态码和响应体.
|
||||
func (c *Context) WANFBuf(code int, obj any) {
|
||||
data, err := wanf.Marshal(obj)
|
||||
if err != nil {
|
||||
c.AddError(fmt.Errorf("failed to encode WANF: %w", err))
|
||||
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to encode WANF: %w", err))
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Set("Content-Type", "application/vnd.wjqserver.wanf; charset=utf-8")
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Writer.Write(data)
|
||||
}
|
||||
|
||||
// HTML 渲染 HTML 模板
|
||||
// 如果 Engine 配置了 HTMLRender,则使用它进行渲染
|
||||
// 否则,会进行简单的字符串输出
|
||||
|
|
@ -469,6 +511,29 @@ func (c *Context) HTML(code int, name string, obj any) {
|
|||
c.Writer.Write(fmt.Appendf(nil, "<!-- HTML rendered for %s -->\n<pre>%v</pre>", name, obj))
|
||||
}
|
||||
|
||||
// HTMLBuf 先将 HTML 模板渲染到 buffer, 成功后再写入状态码和响应体.
|
||||
func (c *Context) HTMLBuf(code int, name string, obj any) {
|
||||
if c.engine != nil && c.engine.HTMLRender != nil {
|
||||
if tpl, ok := c.engine.HTMLRender.(*template.Template); ok {
|
||||
var buf bytes.Buffer
|
||||
err := tpl.ExecuteTemplate(&buf, name, obj)
|
||||
if err != nil {
|
||||
c.AddError(fmt.Errorf("failed to render HTML template '%s': %w", name, err))
|
||||
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to render HTML template '%s': %w", name, err))
|
||||
return
|
||||
}
|
||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Writer.Write(buf.Bytes())
|
||||
return
|
||||
}
|
||||
}
|
||||
// 默认简单输出
|
||||
c.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Writer.Write(fmt.Appendf(nil, "<!-- HTML rendered for %s -->\n<pre>%v</pre>", name, obj))
|
||||
}
|
||||
|
||||
// Redirect 执行 HTTP 重定向
|
||||
// code 应为 3xx 状态码 (如 http.StatusMovedPermanently, http.StatusFound)
|
||||
func (c *Context) Redirect(code int, location string) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue