Skip to content

feat(net/gclient): added query parameter handling function and complete the parameter handling function of DoRequestObj#4639

Open
LanceAdd wants to merge 19 commits into
gogf:masterfrom
LanceAdd:feature/gclient-params
Open

feat(net/gclient): added query parameter handling function and complete the parameter handling function of DoRequestObj#4639
LanceAdd wants to merge 19 commits into
gogf:masterfrom
LanceAdd:feature/gclient-params

Conversation

@LanceAdd

@LanceAdd LanceAdd commented Jan 21, 2026

Copy link
Copy Markdown
Member

feat(net/gclient): added query parameter handling function

描述

  1. 此PR首先为gclient组件添加了增强的查询参数处理功能,支持通过结构体、映射、切片等多种数据类型设置查询参数,显著提升API使用的便捷性和类型安全性。
  2. 改进DoRequestObj参数处理问题,通过结构化的方式支持多种参数类型的分类和处理,实现了OpenApi风格的参数位置标记,使用in 标签指定参数位置,支持 5 种参数类型:pathqueryheadercookiebody

变更内容

1. Client结构体变更

  • Client结构体中添加了queryParams字段用于存储查询参数 (map[string]any)
  • New()函数中初始化queryParamsmake(map[string]any)
  • Clone()方法中添加queryParams的深拷贝逻辑

2. 配置方法新增 (gclient_config.go)

  • SetQuery: 设置单个查询参数
  • SetQueryMap: 批量设置查询参数
  • SetQueryParams: 通过结构体或映射设置查询参数

3. 链式调用方法新增 (gclient_chain.go)

  • Query: 通过映射设置查询参数
  • QueryParams: 通过结构体或映射设置查询参数
  • QueryPair: 设置单个查询参数

4. 请求处理逻辑增强 (gclient_request.go)

  • prepareRequest方法中添加查询参数处理逻辑
  • 使用url2 "net/url"包解析URL以避免命名冲突
  • 实现反射机制处理各种数据类型(基础类型、切片、数组等)
  • 添加对nil值和空切片的特殊处理
  • 实现查询参数与URL中已有参数的智能合并机制

API 描述

配置方法

  • SetQuery(key string, value any) *Client: 设置单个查询参数,支持任意类型值
  • SetQueryMap(m map[string]any) *Client: 批量设置查询参数,接受映射类型参数
  • SetQueryParams(params any) *Client: 设置查询参数,支持结构体、映射等类型,使用gconv.Map进行转换

链式调用方法

  • Query(m map[string]any) *Client: 通过映射设置查询参数,创建新的Client实例
  • QueryParams(params any) *Client: 通过结构体或映射设置查询参数,创建新的Client实例
  • QueryPair(key string, value any) *Client: 设置单个查询参数,创建新的Client实例

功能特性

1. 多数据类型支持

  • 基础类型:string, int, bool, float
  • 结构体:通过gconv.Map转换为映射
  • 映射:直接映射键值对(支持map[string]any
  • 切片类型:使用反射动态处理所有类型的切片,会转换为多个同名查询参数
  • 数组类型:使用反射动态处理所有类型的数组,会转换为多个同名查询参数
  • 空值处理:跳过显式的nil值和空切片

2. 智能参数合并

  • API设置的参数具有更高优先级
  • 自动处理键冲突和无冲突情况
  • 正确处理多值参数(通过queryValues.AddqueryValues.Set

3. 链式调用支持

  • 所有新方法都支持链式调用,符合gclient的设计风格

实现细节

prepareRequest方法中,查询参数处理的关键逻辑:

  • 解析当前请求URL以获取现有的查询参数
  • 遍历Client实例中的queryParams映射
  • 使用反射处理切片和数组类型,将其转换为多个同名参数
  • 对于普通值,直接设置为查询参数
  • 将处理后的查询参数编码并更新请求URL

使用示例

1. 基础使用

// 使用映射设置查询参数
client.Query(map[string]any{
    "page": 1,
    "size": 10,
    "sort": "created_at",
    "active": true,
}).Get(ctx, "http://example.com/api/users")

2. 结构体传参

// 定义查询参数结构体
type UserQuery struct {
    Page     int    `json:"page"`
    Size     int    `json:"size"`
    Sort     string `json:"sort"`
    Keyword  string `json:"keyword"`
}

// 使用结构体设置查询参数
params := UserQuery{Page: 1, Size: 20, Sort: "updated_at", Keyword: "golang"}
client.QueryParams(params).Get(ctx, "http://example.com/api/users")

3. 单个参数设置

// 设置单个查询参数
client.QueryPair("status", "active").Get(ctx, "http://example.com/api/users")

4. 链式调用

// 链式设置多个参数
client.QueryPair("status", "published").
    QueryPair("page", 1).
    QueryPair("featured", true).
    QueryPair("limit", 20).
    Get(ctx, "http://example.com/api/articles")

5. 切片和数组类型使用示例

// 使用字符串切片(会转换为多个同名查询参数)
client.Query(map[string]any{
    "tags": []string{"go", "programming", "web"},  // 生成 ?tags=go&tags=programming&tags=web
    "page": 1,
}).Get(ctx, "http://example.com/api/articles")

// 使用整数切片
client.Query(map[string]any{
    "ids": []int{1, 2, 3, 4},  // 生成 ?ids=1&ids=2&ids=3&ids=4
    "page": 1,
}).Get(ctx, "http://example.com/api/users")

// 使用各种数值类型切片
client.Query(map[string]any{
    "integers": []int32{10, 20, 30},     // 生成 ?integers=10&integers=20&integers=30
    "unsigned": []uint{1, 2, 3},       // 生成 ?unsigned=1&unsigned=2&unsigned=3
    "floats": []float32{1.1, 2.2, 3.3}, // 生成 ?floats=1.1&floats=2.2&floats=3.3
    "page": 1,
}).Get(ctx, "http://example.com/api/data")

6. 与其他配置组合使用

// 与其他客户端配置组合使用
client.SetHeader("Authorization", "Bearer token").
    Query(map[string]any{
        "page": 1,
        "size": 10,
    }).
    Get(ctx, "http://example.com/api/protected-data")

7. URL参数合并示例

// URL本身包含参数,与API设置的参数合并
// 原始URL: http://example.com/api/users?page=1&size=5
// 设置参数: client.Query(map[string]any{"page": 2, "sort": "name"})
// 最终URL: http://example.com/api/users?page=2&size=5&sort=name

向后兼容性

  • 完全向后兼容,不影响现有功能
  • 所有原有API继续正常工作
  • 不改变任何现有行为

性能考量

  • 查询参数存储在map中,内存开销可控
  • 参数处理在请求准备阶段完成,性能影响微小
  • 使用标准库的URL处理函数,效率高

complete the parameter handling function of DoRequestObj

📋 概述

gclient.DoRequestObj 方法增加了基于 in 标签的参数分类功能,支持将请求对象的字段自动分类到不同的 HTTP 请求位置(路径、查询、请求头、Cookie、请求体),提供更灵活和类型安全的 HTTP 客户端使用方式。

✨ 核心功能

1. 支持 in 标签参数分类

现在可以使用 in 标签指定参数的位置,支持 5 种参数类型:

type UserCreateReq struct {
    g.Meta  `path:"/user/{id}" method:"post" mime:"application/json"`
    Id      int    `in:"path"`      // 路径参数
    Token   string `in:"header"`    // 请求头参数
    Page    int    `in:"query"`     // 查询参数
    Session string `in:"cookie"`    // Cookie 参数
    Name    string `json:"name"`    // 请求体参数(默认)
    Age     int    `json:"age"`     // 请求体参数(默认)
}

g.Meta 支持的标签:

  • path - 请求路径(必需)
  • method - HTTP 方法(必需)
  • mime - Content-Type 头(可选,如 "application/json")

实际请求效果:

req := &UserCreateReq{
    Id: 123, Token: "Bearer xxx", Page: 1,
    Session: "session-id", Name: "John", Age: 25,
}
client.DoRequestObj(ctx, req, &res)

// 生成的请求:
// POST /user/123?page=1
// Headers: Token: Bearer xxx, Content-Type: application/json
// Cookies: Session=session-id
// Body: {"name":"John","age":25}

使用 mime 标签控制请求格式:

  • 不指定 mime:默认使用表单数据格式(application/x-www-form-urlencoded)
  • mime:"application/json":使用 JSON 格式发送请求体
  • mime:"multipart/form-data":使用 multipart 格式(用于文件上传)

2. 支持的数据类型

  • 路径参数 (in:"path"):基本类型(int, string, bool 等)
  • 查询参数 (in:"query"):基本类型、切片、数组
  • 请求头 (in:"header"):字符串类型
  • Cookie (in:"cookie"):字符串类型
  • 请求体(默认):所有类型,包括结构体、Map 等复杂类型

类型限制:

// ✅ 正确用法
type Req struct {
    Page   int      `in:"query"`   // 基本类型
    Tags   []string `in:"query"`   // 切片类型
    Filter struct {                // 结构体放在 body
        Name string `json:"name"`
    }
}

// ❌ 错误用法
type Req struct {
    Filter map[string]string `in:"query"`  // Map 不支持作为查询参数
    Data   SomeStruct        `in:"query"`  // 结构体不支持作为查询参数
}

3. 请求体参数的结构体处理

对于请求体参数,支持两种结构体使用方式:

匿名嵌入结构体 - 字段展平:

type UserInfo struct {
    Age   int    `json:"age"`
    Email string `json:"email"`
}

type Req struct {
    g.Meta `path:"/user" method:"post" mime:"application/json"`
    UserInfo  // 匿名嵌入,字段会被展平
    Name string `json:"name"`
}

// 生成的请求体(JSON 格式):
// {"age": 25, "email": "test@example.com", "name": "John"}

命名结构体字段 - 保持嵌套:

type Req struct {
    g.Meta `path:"/user" method:"post" mime:"application/json"`
    User UserInfo `json:"user"`  // 命名字段,保持嵌套
    Name string   `json:"name"`
}

// 生成的请求体(JSON 格式):
// {"user": {"age": 25, "email": "test@example.com"}, "name": "John"}

说明:

  • 使用 mime:"application/json" 标签可以指定使用 JSON 格式发送请求体
  • 不指定 mime 时,默认使用表单数据格式(application/x-www-form-urlencoded)
  • 匿名嵌入结构体的字段会被展平到同一层级
  • 命名结构体字段会保持嵌套结构
  • 这种设计符合 Go 语言的嵌入语义,让结构体组合更加灵活

4. 清晰的参数分类规则

  • in 标签的字段:按标签指定的位置分类
  • 不带 in 标签的字段:默认放入请求体
  • 结构体字段:只能放在请求体中(不带 in 标签)

🎯 使用场景

这个功能特别适合以下场景:

  1. RESTful API 客户端:清晰地定义路径参数、查询参数和请求体
  2. OpenAPI/Swagger 集成:与 OpenAPI 的参数位置定义保持一致
  3. 类型安全的 HTTP 请求:通过结构体定义确保参数类型正确
  4. 代码生成:便于从 API 定义自动生成客户端代码

- 新增 queryParams 字段用于存储查询参数映射
- 实现 Query、QueryParams 和 QueryPair 链式调用方法
- 添加 SetQuery、SetQueryMap 和 SetQueryParams 设置方法
- 支持结构体参数自动转换为查询参数
- 支持切片和数组类型的参数处理
- 实现 nil 值参数跳过逻辑
- 添加 URL 参数合并和覆盖功能
- 完善查询参数的单元测试覆盖
Comment thread net/gclient/gclient_request.go
@gqcn gqcn added the awesome It's awesome! We keep watching. label Jan 21, 2026
@gqcn gqcn requested a review from Copilot January 21, 2026 11:22
@gqcn gqcn changed the title feat(net/gclient): Added query parameter handling function feat(net/gclient): added query parameter handling function Jan 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive query parameter handling capabilities to the gclient HTTP client, enabling developers to set query parameters through multiple convenient methods using various data types including structs, maps, slices, and basic types.

Changes:

  • Added queryParams field to the Client struct to store query parameters
  • Implemented three configuration methods (SetQuery, SetQueryMap, SetQueryParams) and three chaining methods (Query, QueryParams, QueryPair)
  • Enhanced request preparation logic to process and merge query parameters with proper nil/empty value handling and type conversion using reflection

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
net/gclient/gclient.go Added queryParams field to Client struct, initialized in New(), and cloned in Clone() method
net/gclient/gclient_config.go Implemented SetQuery, SetQueryMap, and SetQueryParams configuration methods
net/gclient/gclient_chain.go Added Query, QueryParams, and QueryPair chaining methods for fluent API usage
net/gclient/gclient_request.go Enhanced prepareRequest with query parameter processing logic using reflection to handle slices/arrays and proper URL merging
net/gclient/gclient_z_unit_query_params_test.go Comprehensive test suite covering basic types, structs, slices/arrays, URL merging, chaining, special characters, and integration scenarios
net/gclient/gclient_z_unit_query_nil_test.go Extensive tests for nil value handling including nil pointers, nil slices, empty slices/arrays, and mixed scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread net/gclient/gclient_request.go Outdated
Comment thread net/gclient/gclient_request.go Outdated
Comment thread net/gclient/gclient_request.go Outdated
Comment thread net/gclient/gclient_request.go Outdated
Comment thread net/gclient/gclient_z_unit_query_params_test.go
Comment thread net/gclient/gclient_config.go
LanceAdd and others added 15 commits January 22, 2026 10:18
- 移除不必要的 url2 包导入
- 直接操作 URL 结构体字段而非重新解析 URL 字符串
- 提高高吞吐量应用的性能避免不必要的字符串操作
- 更新反射指针解引用注释说明完全解引用所有层级指针
- 简化查询参数编码直接设置到请求 URL 对象
- 新增mergeQueryParams函数统一处理URL查询参数合并
- 新增normalizeURL函数标准化URL前缀和协议
- 新增buildRequestParams函数构建请求参数
- 新增enhanceRequest函数增强请求上下文、头部和认证
- 新增createNormalPostRequest函数创建普通POST请求
- 新增createMultipartRequest函数创建多部分表单请求
- 新增createGetRequest函数创建GET请求并处理查询参数
- 新增createPostRequest函数创建POST/PUT/DELETE请求
- 优化prepareRequest函数结构化请求构建流程
- 改进参数处理优先级:queryParams > dataParams > urlParams
- 修复noUrlEncode标志对查询参数编码的影响
- 提升代码可读性和维护性
- 移除了单部分参数的空字符串赋值逻辑
- 添加了完整的查询参数与数据参数交互测试
- 验证了Query/QueryParams/QueryPair方法与Get方法数据参数的集成
- 确保查询参数优先级高于数据参数
- 测试了多种参数类型的组合场景
- 移除 unused empty 包依赖
- 在 SetQueryParam 方法中过滤 nil 值以保持一致性
- 在 SetQueryParams 方法中过滤 nil 值以保持一致性
- 简化 IsNil 检查逻辑直接使用 != nil 判断
- 新增GetMergedURL方法用于获取合并后的URL而不发送请求
- 添加GetMergedURL单元测试验证不同HTTP方法的行为
- 完善所有HTTP方法的查询参数功能测试
- 支持结构体、切片、数组等多种查询参数类型
- 实现查询参数与URL参数的合并逻辑
- 添加查询参数与请求体数据的组合测试
- 新增GetBodyMap方法仅获取请求体参数
- 提取URL参数解析逻辑到独立函数parseUnEncodedParams
- 提取查询字符串构建逻辑到独立函数buildUnEncodedQuery
- 添加getMediaType方法安全解析Content-Type头部
- 将上下文参数传递给相关请求构建函数
- 移除重复的参数合并代码并优化流程
- 添加内部日志记录用于调试目的
- 实现 in 标签参数分类,支持 path、query、header、cookie 和 body 参数
- 添加路径参数替换和查询参数映射功能
- 支持嵌入结构体字段自动展平
- 实现命名结构体字段特殊处理逻辑
- 添加对切片和映射类型查询参数的支持
- 新增文件上传参数处理机制
- 完善错误处理和参数验证逻辑
- 补充单元测试覆盖各种参数组合场景
- 将多个返回值改为结构体返回,提高代码可读性
- 新增 requestParams 结构体统一管理各类参数
- 修改 classifyRequestParams 方法返回 *requestParams 指针
- 更新所有参数访问方式从独立变量到结构体字段
- 简化错误返回逻辑,统一错误处理流程
- 优化参数分类和赋值的代码结构
@LanceAdd LanceAdd changed the title feat(net/gclient): added query parameter handling function feat(net/gclient): added query parameter handling function and complete the parameter handling function of DoRequestObj Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awesome It's awesome! We keep watching.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants