跳到主要内容

响应器

本节将介绍如何使用响应器。

简介​

响应器的作用是统一响应数据结构,并高效地处理如 HTTP 状态码、错误码、错误信息等数据。

API 选项​

在前文中提到,响应器会处理 HTTP 状态码、错误码和错误信息,其处理策略由配置项决定。这些配置项对开发者开放,使其能够更灵活地满足不同的使用需求。
这些配置内容被称为 API 选项,开发者可以通过如下方式进行设置:

main.go
import (
"github.com/keepchen/go-sail/v3/constants"
"github.com/keepchen/go-sail/v3/http/api"
"github.com/keepchen/go-sail/v3/sail/config"
)

const ErrNone = sailConstants.CodeType(200)

var (
conf = &config.Config{}
option = &api.Option{
Timezone: constants.DefaultTimeZone,
ErrNoneCode: ErrNone,
ErrNoneCodeMsg: "SUCCESS",
ForceHttpCode200: true,
}
)

func main() {
sail.
WakeupHttp("go-sail", conf).
SetupApiOption(option).
Hook(registerRoutes, nil, nil).
Launch()
}

目前,API 选项支持以下配置项:

项目说明默认值
Timezone时间信息的时区"Aisa/Shanghai"
ErrNoneCode无错误时的错误码0
ErrNoneCodeMsg无错误时的错误信息"SUCCESS"
ErrRequestParamsInvalidCode请求参数错误的错误码100000
ErrRequestParamsInvalidCodeMsg请求参数错误的错误信息"Bad request parameters"
ErrAuthorizationTokenInvalidCode授权信息无效的错误码100001
ErrAuthorizationTokenInvalidCodeMsg授权信息无效的错误信息"Authorization token invalid"
ErrInternalServerErrorCode服务器内部错误的错误码999999
ErrInternalServerErrorCodeMsg服务器内部错误的错误信息"Internal server error"
ForceHttpCode200是否强制返回 200 HTTP 状态码false
DetectAcceptLanguage是否检测客户端语言false
LanguageCode语言代码"en"
FuncBeforeWrite响应写入前的处理函数nil
EmptyDataStruct空 data 字段的数据表现形式nil

Timezone​

Timezone 选项决定响应器处理时间时所使用的时区。目前时间信息仅使用时间戳,因此该配置项将在后续更新中发挥更大作用。

ErrNone 和 ErrNoneCodeMsg​

No Error 表示无错误时(即处理成功)的代码值和代码信息。默认情况下,代码值为 0,代码信息为 SUCCESS。
如果响应指定的无错误码等于该值,且 ForceHttpCode200 选项未设置为 true,则 HTTP 状态码会被设置为非 200。

ErrRequestParamsInvalidCode 和 ErrRequestParamsInvalidCodeMsg​

请求参数无效时的错误码和错误信息。当 ForceHttpCode200 未设置为 true 时,HTTP 状态码会被设置为 400。

ErrAuthorizationTokenInvalidCode 和 ErrAuthorizationTokenInvalidCodeMsg​

授权信息无效时的错误码和错误信息。当 ForceHttpCode200 未设置为 true 时,HTTP 状态码会被设置为 401。

ErrInternalServerErrorCode 和 ErrInternalServerErrorCodeMsg​

服务器内部错误时的错误码和错误信息。当 ForceHttpCode200 未设置为 true 时,HTTP 状态码会被设置为 500。

ForceHttpCode200​

当该值设置为 true 时,HTTP 状态码将不再根据错误码判断,而是直接返回 200。

提示

该选项适用于需要严格 HTTP 状态码响应,或仅通过错误码判断的场景。
它代表了不同的接口返回设计思想。

DetectAcceptLanguage​

指定响应器是否检测客户端语言,并从注入的语言代码表中提取指定客户端语言的内容。

提示

该选项需要中间件 DetectUserAgentLanguage 的配合。源码可在 http/middleware/detectuseragentlanguage.go 找到。

LanguageCode​

LanguageCode 选项指定响应器返回错误信息时所用的语言。当 DetectAcceptLanguage 未生效时作为兜底。

FuncBeforeWrite​

设置响应写入前的处理函数,允许开发者拦截并处理响应内容。需要注意的是,这里的响应内容是实际响应的副本,无法修改真正的响应内容,但可以用于日志等操作。

EmptyDataStruct​

通常情况下,data 字段为空时会被序列化为 null。部分客户端可能不期望这种行为,此时可通过该选项指定特定的空数据结构,如空数组([])、空对象()、数字、布尔值等。

错误码​

在实际业务开发中,通常会定义大量的错误码和错误信息。为了让响应器能够正确识别这些错误码和错误信息,需要提前进行注册。

注册​

你可以通过如下方式进行注册,这是一种较为常见且简单的方式。

main.go
type ErrorCode int

func (v ErrorCode) Int() int {
return int(v)
}

const (
ErrUserNotExist ErrorCode = 1000
ErrUserAlreadyExist ErrorCode = 1001
ErrUsernameAndPasswordNotMatch ErrorCode = 1002
)

var codeMsgMap = map[ErrorCode]string{
ErrUserNotExist: "User not exist",
ErrUserAlreadyExist: "User already exist",
ErrUsernameAndPasswordNotMatch: "Username and password not match",
}


var once sync.Once

func init() {
once.Do(func() {
time.AfterFunc(time.Second*2, func() {
for code, msg := range codeMsgMap {
sail.Code().Register("en", code.Int(), msg)
}
})
})
}

使用方式​

之后,你可以这样使用:

main.go
sail.Response(c).Bundle(ErrUserNotExist.Int(), nil).Send()
提示

同样,你也可以通过这种方式注册其他语言的错误码和错误信息。

响应包装器​

响应器目前提供了三种不同的包装器,以适应不同的场景。

我们假设有如下数据结构定义:

main.go
import "github.com/keepchen/go-sail/http/pojo/dto"

type UserInfo struct {
dto.Base
Data struct {
Nickname string `json:"nickname" validate:"required" format:"string"`
Age number `json:"nickname" validate:"required" format:"number"`
} `json:"data" validate:"required" format:"object"`
}

func (v UserInfo) GetData() interface{} {
return v.Data
}

type SimpleUser struct {
Nickname string `json:"nickname" validate:"required" format:"string"`
Age number `json:"nickname" validate:"required" format:"number"`
}

Builder​

Builder 包装器的错误码参数类型需要是 Go-Sail 的 constants.ICodeType,响应数据类型需要是 dto.IResponse。

main.go
var userInfo UserInfo
sail.Response(c).Builder(constants.XX, resp).Send()

Wrap​

Wrap 包装器的错误码参数类型需要是 Go-Sail 的 constants.ICodeType,响应数据类型需要是 interface。

main.go
var userInfo SimpleUser
sail.Response(c).Wrap(constants.XX, resp).Send()

Bundle​

Bundle 包装器的错误码参数类型需要是 int,响应数据类型需要是 interface。在易用性方面,Bundle 是最简单的。

main.go
var userInfo SimpleUser
sail.Response(c).Wrap(200, resp).Send()

这三种包装器分别代表了不同的响应数据结构和错误码调用方式。
UserInfo 数据结构是完整的数据定义,而 SimpleUser 是精简的数据定义。在生成 Swagger 文档时,它们的表现会有所不同,具体取决于开发者的选择。

发送响应​

目前提供了多种语法糖用于发送响应。

Send​

main.go
var userInfo SimpleUser
sail.Response(c).Wrap(200, resp).Send()

Data​

该函数返回成功数据。

main.go
var userInfo SimpleUser
sail.Response(c).Data(resp)

Success​

该函数返回空的成功数据,等价于 Data(nil)。

main.go
sail.Response(c).Success()

SendWithCode​

该函数可以强制返回指定的 HTTP 状态码,在某些特殊场景下非常有用。

main.go
var userInfo SimpleUser
sail.Response(c).Wrap([someErrorCode], resp).SendWithCode(500)

Failure​

该函数在错误码为 Go-Sail 内置的 constants.ErrRequestParamsInvalid 时返回错误信息,HTTP 状态码由 API 配置项决定。

main.go
sail.Response(c).Failure()

Failure200​

该函数在发生错误时返回错误信息,错误码由调用方传入,HTTP 状态码为 200。

main.go
sail.Response(c).Failure200([code], nil)

Failure400​

该函数在发生错误时返回错误信息,错误码由调用方传入,HTTP 状态码为 400。

main.go
sail.Response(c).Failure400([code], nil)

Failure500​

该函数在发生错误时返回错误信息,错误码由调用方传入,HTTP 状态码为 500。

main.go
sail.Response(c).Failure500([code], nil)