--- title: Go 服务端 SDK --- # Go 服务端 SDK 官方 Go 服务端 SDK —— `github.com/Captcha-La/captchala-go`。 SDK 帮你做三件事: 1. **校验**(Validate)—— 验证浏览器 SDK 返回的 `pt_` pass token。 2. **签发**(Issue)—— 签发一次性 `sct_` server token, 将本次挑战绑定到具体 action / IP / UID。 3. **审核**(Moderate)—— 多模态(文本 + 图片)内容审核, 走 dashboard 同款 OpenAI 兼容管道。 ## 安装 ```bash go get github.com/Captcha-La/captchala-go ``` 只用标准库, 无外部依赖。 ## 校验(`pt_` token) 传入终端用户的 IP(从 `CF-Connecting-IP` / `X-Forwarded-For` 获取, 回退到 `RemoteAddr`)。可选,但**建议传** —— 用于额外的风控校验。 ```go import captchala "github.com/Captcha-La/captchala-go" client := captchala.NewClient(appKey, appSecret) func handler(w http.ResponseWriter, r *http.Request) { token := r.FormValue("captcha_token") result, err := client.ValidateWithClientIP(token, false, clientIP(r)) if err != nil || !result.Valid { http.Error(w, result.Error, http.StatusBadRequest) return } // Verification passed; proceed with the request. // result.CaptchaArgs has Platform / UserIP / Referer / Pkg / SolvedAt / RiskScore } // Real end-user IP behind a CDN / proxy func clientIP(r *http.Request) string { if ip := r.Header.Get("CF-Connecting-IP"); ip != "" { return ip } if xff := r.Header.Get("X-Forwarded-For"); xff != "" { return strings.TrimSpace(strings.Split(xff, ",")[0]) } host, _, _ := net.SplitHostPort(r.RemoteAddr) return host } ``` 手头没有 IP?用 `client.Validate(token)` —— 校验照常工作, 只是少了基于 IP 的 额外风控信号。 如果原 `server_token` 带了 `bind_uid`, 校验时核对 uid: ```go if result.UID != expectedUserID { http.Error(w, "user mismatch", http.StatusBadRequest) return } ``` 解题时的上下文也通过 `result.CaptchaArgs` 返回供参考: ```go ip := result.CaptchaArgs.UserIP // 解题时记录的访客 IP ``` ## 签发 server token 注册 / 登录 / 支付等高价值场景推荐流程:后端签发一次性 `sct_` token, 下发给前端, 浏览器作为 `serverToken` 用。单次消费, 绑定 action, 可选绑定 IP / UID。 ```go issue, err := client.IssueServerTokenWithOptions("login", captchala.IssueOptions{ BindingIP: userIP, // 不同 IP 来兑换会被拒 TTL: 300, // 秒 MaxUses: 5, // SDK 重试预算 BindUID: userID, // 配合 ValidateResult.UID 校验 }) if err != nil || !issue.OK { http.Error(w, issue.Error, http.StatusBadRequest) return } // 把 issue.Token 下发给浏览器 ``` 默认参数快捷方式: ```go issue, err := client.IssueServerToken("login") ``` ## 内容审核 多模态 —— 接受 `ModerationItem` 切片(文本 / image_url 混合, OpenAI 兼容): ```go result, err := client.ModerationCheck([]captchala.ModerationItem{ captchala.TextItem(userComment), captchala.ImageURLItem(uploadedImageURL), }, userID) if err != nil || !result.OK { http.Error(w, result.Error, http.StatusBadRequest) return } if result.Flagged { if result.HasCategory("violence", "csam") { // 硬阻断 } } ``` 纯文本快捷方式: ```go result, err := client.ModerationText("user comment here", userID) ``` Category 列表由上游模型决定, 用 `result.Categories` 防御性遍历, 不要硬编码固定集合。 ## 类型 | 类型 | 字段 | |---|---| | `ValidateResult` | `Valid`、`Error`、`UID`、`ChallengeID`、`Action`、`Offline`、`ClientOnly`、`Warning`、`CaptchaArgs` | | `CaptchaArgs` | `Platform`、`UserIP`、`Referer`、`Pkg`、`SolvedAt`、`RiskScore`(纯信息字段, 切勿基于这些放行)| | `IssueResult` | `OK`、`Token`、`ExpiresIn`、`IssuedAt`、`Error`、`Message` | | `IssueOptions` | `BindingIP`、`TTL`、`MaxUses`、`BindUID` | | `ModerationItem` | `Type`、`Text`、`ImageURL`(用 `TextItem()` / `ImageURLItem()` 辅助函数构造)| | `ModerationResult` | `OK`、`Flagged`、`Categories`、`ContentType`、`Raw`、`Error`、`Message`;方法 `HasCategory(...names)` | ## 链接 - [pkg.go.dev](https://pkg.go.dev/github.com/Captcha-La/captchala-go) · [GitHub](https://github.com/Captcha-La/captchala-go) - [Web SDK 总览](/zh-CN/web-sdk) · [API 参考](/zh-CN/api-reference)