You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
3.3 KiB
143 lines
3.3 KiB
package rsp
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"zestack.dev/slim"
|
|
)
|
|
|
|
var (
|
|
// TextMarshaller 将 Map 转化成文本格式用于响应给请求者
|
|
TextMarshaller func(map[string]any) (string, error)
|
|
// HtmlMarshaller 将 Map 转换成超文本格式用于响应给请求者
|
|
HtmlMarshaller func(map[string]any) (string, error)
|
|
// JsonpCallbacks 默认 JSONP 查询的字段
|
|
JsonpCallbacks []string
|
|
// DefaultJsonpCallback 默认查询的 JSONP 函数字段名
|
|
DefaultJsonpCallback string
|
|
)
|
|
|
|
func init() {
|
|
TextMarshaller = toText
|
|
HtmlMarshaller = toText
|
|
JsonpCallbacks = []string{"callback", "cb", "jsonp"}
|
|
DefaultJsonpCallback = "callback"
|
|
}
|
|
|
|
func toText(m map[string]any) (string, error) {
|
|
buf := &bytes.Buffer{}
|
|
enc := json.NewEncoder(buf)
|
|
enc.SetEscapeHTML(true)
|
|
if err := enc.Encode(m); err != nil {
|
|
return "", err
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func respond(c slim.Context, o *response) (err error) {
|
|
defer func() {
|
|
if err != nil {
|
|
c.Logger().Error(err.Error())
|
|
}
|
|
}()
|
|
// 如果已经输出过,就忽略
|
|
if c.Written() {
|
|
return nil
|
|
}
|
|
// 设置报头
|
|
if o.headers != nil {
|
|
for key, value := range o.headers {
|
|
c.SetHeader(key, value)
|
|
}
|
|
}
|
|
// 设置 cookie
|
|
if o.cookies != nil {
|
|
for _, cookie := range o.cookies {
|
|
c.SetCookie(cookie)
|
|
}
|
|
}
|
|
m, status := o.result(c)
|
|
// HEAD 请求没有结果
|
|
r := c.Request()
|
|
if r.Method == http.MethodHead {
|
|
return c.NoContent(status)
|
|
}
|
|
// 根据报头响应不同的格式
|
|
switch c.Accepts("html", "json", "jsonp", "xml", "text", "text/*") {
|
|
case "html":
|
|
var html string
|
|
if html, err = HtmlMarshaller(m); err == nil {
|
|
err = c.HTML(status, html)
|
|
}
|
|
case "json":
|
|
err = c.JSON(status, m)
|
|
case "jsonp":
|
|
qs := c.Request().URL.Query()
|
|
for _, name := range JsonpCallbacks {
|
|
if cb := qs.Get(name); cb != "" {
|
|
err = c.JSONP(status, cb, m)
|
|
return
|
|
}
|
|
}
|
|
err = c.JSONP(status, DefaultJsonpCallback, m)
|
|
case "xml":
|
|
err = c.XML(status, m)
|
|
case "text", "text/*":
|
|
var text string
|
|
if text, err = TextMarshaller(m); err == nil {
|
|
err = c.String(status, text)
|
|
}
|
|
default:
|
|
err = c.JSON(status, m)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Respond 自定义响应
|
|
func Respond(c slim.Context, opts ...Option) error {
|
|
o := response{status: http.StatusOK}
|
|
for _, option := range opts {
|
|
option(&o)
|
|
}
|
|
return respond(c, &o)
|
|
}
|
|
|
|
// Ok 响应成功请求
|
|
func Ok(c slim.Context, data any) error {
|
|
return Respond(c, Data(data))
|
|
}
|
|
|
|
// Created 表示数据创建成功
|
|
func Created(c slim.Context, data any) error {
|
|
return Respond(c, Data(data), StatusCode(http.StatusCreated))
|
|
}
|
|
|
|
// Deleted 表示数据删除成功
|
|
func Deleted(c slim.Context, data ...any) error {
|
|
if len(data) > 0 {
|
|
return Respond(c, StatusCode(http.StatusOK), Data(data[0]))
|
|
}
|
|
return Respond(c, StatusCode(http.StatusOK))
|
|
}
|
|
|
|
// NotFound 响应访问的资源不存在
|
|
func NotFound(c slim.Context) error {
|
|
return Respond(c, StatusCode(http.StatusNotFound))
|
|
}
|
|
|
|
// Accepted 响应一个异步操作,比如任务调度等
|
|
func Accepted(c slim.Context, data any) error {
|
|
return Respond(c, Data(data), StatusCode(http.StatusAccepted))
|
|
}
|
|
|
|
// Fail 响应一个错误
|
|
func Fail(c slim.Context, err error, opts ...Option) error {
|
|
o := response{status: http.StatusInternalServerError}
|
|
for _, option := range opts {
|
|
option(&o)
|
|
}
|
|
o.err = err
|
|
return respond(c, &o)
|
|
}
|
|
|