用 net/http 编写轻量 github 用户仓库数查询服务:校验用户名格式,设 user-agent 和超时,用 url.url 构建请求,正确解析 json 响应中的 public_repos 字段。

怎么用 Go 写个能查 GitHub 用户仓库数的 HTTP 服务
直接上手:用 net/http 起一个最简 API,不引入框架,避免初期被路由、中间件绕晕。重点是让请求能发出去、响应能收回来、JSON 能解出来。
常见错误现象:json: cannot unmarshal object into Go struct —— 大多因为 GitHub API 返回结构嵌套深,但你定义的 struct 字段没对齐(比如漏了 user 外层包了一层 data),或字段名没加 json tag。
- GitHub REST API v3 的用户信息接口是
GET https://api.github.com/users/{username},返回里public_repos是整型字段,直接映射到int即可 - 必须设
User-Agent请求头,否则 GitHub 会返回403 Forbidden(错误信息里明确写"message": "API rate limit exceeded"或更直白的"message": "You must provide a User-Agent header.") - 别用
http.Get硬编码 URL 拼接,改用url.URL+url.Values构建,防特殊字符(比如用户名含+或/)
为什么不用 github.com/google/go-github/v52 这类 SDK
不是不能用,而是初级阶段过早引入 SDK,反而掩盖了 HTTP 请求本质和错误处理逻辑。SDK 把重试、分页、鉴权都封装了,但你连 404 和 422 都分不清时,SDK 只会让错误更难定位。
使用场景:只查单个用户公开仓库数,不需要分页、组织成员列表、PR 状态等——这种需求,手写 http.Client + json.Unmarshal 更轻、更可控。
立即学习“go语言免费学习笔记(深入)”;
- SDK 默认启用 rate limit 自动等待,但你根本没配 token,它就卡在那儿不动,控制台也没提示
- SDK 返回的 struct 字段名常带下划线(如
Public_Repos),而 Go 标准库 json 解析默认按首字母大小写匹配,容易漏字段 - 如果后续要加缓存或日志,SDK 的调用链埋点比原生
Do调用难插桩
怎么安全传入用户名并防止路径遍历或注入
GitHub 用户名规则是:只能含 ASCII 字母、数字、短横线(-),且不能以短横线开头或结尾,长度 1–39。不校验就直接拼进 URL,可能被构造为 ../../etc/passwd 类路径穿越(虽然 GitHub API 不走文件系统,但养成习惯很重要)。
参数差异:URL 路径参数(path param)和查询参数(query param)处理方式不同。用户名必须是 path param,因为它是资源标识符;其他如 per_page 才该放 query。
- 用
regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\-]{0,38}[a-zA-Z0-9]$`)做白名单校验,比strings.Contains黑名单更可靠 - 校验失败立刻返回
400 Bad Request并带上具体错误原因(比如"invalid username format"),别吞掉或返回空 JSON - 别在日志里打印完整请求 URL,防止用户名被误记入日志系统(尤其部署后有人测
admin、root这类敏感词)
本地调试时总遇到 connection refused 或 timeout 怎么办
八成是没设超时,http.DefaultClient 的默认 Transport 没配 Timeout,一卡就是几十秒,看着像挂了。Go 的 HTTP 客户端默认不设限,得自己管。
性能 / 兼容性影响:不设超时,线上并发高时 goroutine 积压,内存暴涨;本地调试时则表现为命令行卡住、IDE 调试器失联。
- 必须显式创建
http.Client,设置Timeout: 10 * time.Second - 别忽略
resp.Body.Close(),否则连接不释放,跑几次就触发too many open files - 用
curl -v http://localhost:8080/user/octocat看原始响应头和状态码,比浏览器更准——浏览器可能缓存 304,而你代码其实已报错
事情说清了就结束










