Skip to content

refactor(net/gclient): split prepareRequest into focused helper functions - #4890

Open
LanceAdd wants to merge 1 commit into
gogf:masterfrom
LanceAdd:fix/session
Open

LanceAdd wants to merge 1 commit into
gogf:masterfrom
LanceAdd:fix/session

Conversation

@LanceAdd

Copy link
Copy Markdown
Member

背景

net/gclient 的 prepareRequest 是每个请求都要走的"组装请求"函数:从拼 URL 到最终发出请求前的所有准备都在这一个函数里,212 行、约 30 个判断点、最深 5 层嵌套。它同时负责五件事:

职责 具体做什么
URL 规整 拼 prefix、补 http:// 协议头
参数序列化 按 Content-Type 决定 JSON / XML / 表单编码
请求体构造 GET 拼 query、multipart 文件上传(@file:)、普通 body
Content-Type 自动探测 body 看着像 JSON / 表单时自动补上 Content-Type
请求选项注入 ctx、自定义 header、Host、Cookie、BasicAuth

带来的现实问题:难读,难改

改动

一、拆解(对行为零影响)

prepareRequest 收缩为 27 行的编排(先编码参数 → 按三种形态装配请求 → 注入选项),拆出 8 个私有辅助函数,全部留在原文件 net/gclient/gclient_request.go:

辅助函数 职责
prepareRequestURL 拼 prefix、补协议
resolveRequestMediaType 解析 Content-Type(全局一处,带解析失败兜底)
encodeRequestParams 参数序列化 + 返回"是否允许文件上传"
newGetRequest GET:参数进 query 还是 body
newMultipartRequest multipart 请求装配
writeMultipartItem 单个 k=v 项写入(含 @file: 上传判定)
newNormalRequest 普通 body + Content-Type 自动探测
applyRequestOptions ctx → 自定义 header → Host → Cookie → BasicAuth

顺带消掉的重复与噪音:Content-Type 二次解析与重复兜底、err 遮蔽、5 层嵌套(现在最深 3 层)。

二、修复:URL 协议判断

拆解过程中发现 URL 协议判断有一处 bug(域名含 http 子串会漏拼协议头)。原来的判据是"URL 整串里出现过 http 字样",既不是"有没有协议头",也不是"协议头是不是 http",因此漏拼甚至拼坏三类输入,一并修复:

输入 修复前 修复后
myhttpservice.com/api(域名含 http 子串) 漏拼协议头,请求报 unsupported protocol scheme "" http://myhttpservice.com/api
example.com/a?u=http://b(查询串含 http) 同上,漏拼报错 http://example.com/a?u=http://b
ftp://x.com/a(非 http 协议) 被拼成 http://ftp://x.com/a,实际去连主机名 ftp(静默打错主机) 保持原样交给标准库,报 unsupported protocol scheme "ftp"

新判据:^[a-zA-Z][a-zA-Z0-9+.-]*://(锚定开头、且要求带 ://)。

为什么不直接 url.Parse 后看 Scheme:localhost:8000 会被解析成 Scheme=localhost、127.0.0.1:8000 会直接解析报错,两种都要额外兜底才能救回来;而"必须带 ://"让 host:port 天然不匹配,不需要任何特判。

兼容性

  • 拆解部分零行为变化:prepareRequest 是私有方法、唯一调用点是 DoRequest,无公开 API 变化;错误消息文本、各步骤执行顺序(header 注入在自动探测之后、Cookie 在 Host 之后等)、GET 无参数也构造空 body 等细节全部原样保留。
  • 修复部分只影响"URL 未写协议头"时的补全:上表三类输入由报错/打错主机变为正常或明确报错;其余输入(http://x、HTTP://X、localhost:8000、127.0.0.1:8000、带 prefix 的相对路径等)修复前后完全一致。

测试

  • 新增 net/gclient/gclient_z_unit_internal_test.go:
    • Test_PrepareRequestURL:14 条 table 用例,钉住上表全部输入 + 大小写协议头 + 空串 + prefix 组合(含 trim);
    • Test_PrepareRequest_SchemeCompleted:走完整 prepareRequest,断言 req.URL 的 Scheme / Host / Path。
  • 已运行:go test ./net/gclient/ ./internal/httputil/ 全绿(gclient 约 30s,覆盖文件上传、特殊字符参数、JSON body 含 @file: 不触发上传、表单字段截断等边界用例);net/ghttp 定向(Test_Params_File* 9 个、Test_Params_Struct* 3 个、Test_Client*)通过。
  • gofmt 干净,golangci-lint 对改动文件无告警。

复现

go test ./net/gclient/ -run "Test_PrepareRequest" -count=1 -v
go test ./net/gclient/ ./internal/httputil/ -count=1
go test ./net/ghttp/ -run "Test_Params_File|Test_Params_Struct|Test_Client" -count=1

…ions

Extract url preparation, media type resolution, params encoding, request
body building and option applying into dedicated helpers, so each step
can be read and tested independently.

The url protocol completion is also fixed: the previous check of "url
contains http" missed urls with "http" inside the host (eg.
"myhttpservice.com") and mangled urls with non-http schemes. It is now
scheme detection anchored at the beginning of the url.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant