# gaore-common-sdk-go ### 1.目录架构 ``` ├── README.md ├── sdk │   ├── auth `认证类` │   ├── client.go `客户端主入口类` │   ├── config.go │   ├── requests `请求类` │   ├── responses `响应类` │   └── utils `工具类` └── services └── jedi ``` ### 2.引入 ```go go get -u golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk ``` 或 Go Module ```go import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" ``` ### 3.服务端认证及返回处理 调用 `auth.UnSign` 方法,提供`*http.Request`请求实例,以及`signer.Signer` 签名器(签名器需要包括凭据) 即可完成整个验签过程 这里以`beego`为例 : ```go package applications import ( "github.com/astaxie/beego" "github.com/astaxie/beego/context" "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth" "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/signers" "golib.gaore.com/GaoreGo/grlogs" ) func init() { // 过滤器 beego.InsertFilter("/api/*", beego.BeforeRouter, func(context *context.Context) { httpRequest := context.Request err := auth.UnSign(httpRequest, signers.NewAccessKeySigner(&credentials.AccessKeyCredential{ AccessKeyId: "aaaaaa", AccessKeySecret: "bbbbbb", AccessKeyFrom: context.Input.Param("access_from"), })) if err != nil { resp := response.NewJsonByDefaultFailed() resp.Msg = err.Error() resp.Code = 10086 var ( hasIndent = beego.BConfig.RunMode != beego.PROD ) context.Output.Status = 500 context.Output.JSON(resp, hasIndent, false) } }) } ``` 服务端返回的响应体为以下结构的json字符流, `code`,`status`,`msg` 这三个字段*最好*要包含且数据类型要一致 , `data` 部分为业务内容,自行定义 ```json { "code": 1001, "msg": "不能为空", "status": false, "data": { ... } } ``` ### 4.sdk编写 在`services`目录下以服务归类新建文件夹, 如`jedi`为短信服务,以 `RpcRequest` 和 `BaseResponse` 以基类写好请求子类和响应子类。一个请求接口对应一对请求和响应类。 ```go import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk" const ( HOST = "jedi" // 如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com VERSION = "2020-08-04" ) type Client struct { sdk.Client } func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) { client = &Client{} err = client.InitWithAccessKey(accesskey, secrect, source) return } func (c *Client) Test(req *DemoTestRequest) (response *DemoTestResponse, err error) { response = CreateDemoTestResponse() err = c.DoAction(req, response) return } ``` 请求类,对参数用标签解释, 如 `position:"Query" field:"param_1" default:""` , 有三个字段 `position` , `field`, `default` - `position` 为标志该参数为请求体对应的位置, `Query` query参数, `Body` post请求体参数, `Head`请求头参数 - `field` 解释成参数实际名称 - `default` 默认值 ```go type DemoTestRequest struct { *requests.RpcRequest Param1 string `position:"Query" field:"param_1" default:"" ` Param2 int `position:"Query" field:"param_2" default:"10086" ` Param3 bool `position:"Query" field:"param_3" default:"false" ` } ``` 对应解释成http请求为: ```go GET param_1=111¶m_2=10086¶m_3=false ``` 完整示例: ```go package jedi import ( "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses" ) // 定义请求体 type DemoTestRequest struct { *requests.RpcRequest Param1 string `position:"Query" field:"param_1" default:"" ` Param2 int `position:"Query" field:"param_2" default:"10086" ` Param3 bool `position:"Query" field:"param_3" default:"false" ` } func CreateDemoTestRequest() (req *DemoTestRequest) { req = &DemoTestRequest{RpcRequest: &requests.RpcRequest{}} // InitWithApiInfo 初始化请求,有三个参数,域名,版本,和路径 // 域名参数如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com req.InitWithApiInfo(HOST, VERSION, "/api/sms/Index") // 定义 请求方法 POST 或 GET req.Method = requests.GET return } // 定义响应体 type DemoTestResponse struct { *responses.BaseResponse Data DemoTestResponseData `json:"data"` } type DemoTestResponseData struct { Account string `json:"account"` Total int `json:"total"` } func CreateDemoTestResponse() *DemoTestResponse { return &DemoTestResponse{ BaseResponse: &responses.BaseResponse{}, } } ``` 终端调试打开方式, 需要在系统环境变量上加入(三选一): ``` DEBUG=sdk,signer,request ``` ### 5.测试用例编写要求 新增或修改 `services/*` 下的接口封装时,**必须**配套可编译的测试,并遵循下列约定(风格可参考 `services/cs/client_test.go` 与 `services/game/client_test.go`)。 #### 5.1 单测职责(一条用例里要覆盖什么) - **请求侧**:构造 `Create*Request`,填入业务参数后调用 `requests.InitParam(req)`,再断言 HTTP 方法、`GetActionName()` 路径、以及 Query/Form 等关键参数是否注入正确。 - **调用侧**:使用本服务 `NewClient()`(或项目约定的构造方式)**真实调用** `Client` 上对应方法,覆盖 `DoAction` 与签名、序列化整条链路。 - **响应侧**:断言 `err == nil`、响应非 `nil`,并对业务字段做断言(如 `Code`、`Msg`、`Data` 及关键业务 ID、类型等);**必须**通过 `fmt.Printf` 打印返回内容,便于人工核对逻辑是否正确。 - **风格**:与 `cs` 一致时优先使用 `t.Error` / `t.Errorf` + `return` 早退出;断言失败时除 `t.Errorf` 外可再 `fmt.Printf("%#+v\n", resp)`(及对 `*resp.Data`)便于排错。 #### 5.2 组织方式 - **同一能力的多条场景**(如白名单与黑名单):可拆成 `TestXxx`、`TestXxxBlack` 等若干函数,**每个函数内**仍应完整包含「请求校验 → 真实调用 → 响应断言 → 打印」,避免把断言拆成大量只测一行的小函数。 - **禁止**仅写「只校验 `InitParam`、不调 Client」的孤立用例作为唯一测试;若需 mock(无网/CI),可另加辅助函数,但不应替代上述真实调用用例作为唯一验收。 #### 5.3 输出与可读性 - 使用 `fmt.Printf("%#+v\n", resp)` 打印完整响应结构体;若 `Data` 为指针,再打印 `fmt.Printf("%#+v\n", *resp.Data)`。 - 测试函数顶部用简短中文注释说明测的是哪条接口、什么场景。 #### 5.4 运行 ```bash go test ./services/<包名> -run Test<名称> -v ```