Skip to content

feat(ghttp): 支持文件上传字段的嵌套结构解析 #4234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

hinego
Copy link
Contributor

@hinego hinego commented Apr 7, 2025

当前问题,使用嵌套字段时无法自动绑定到嵌套字段的文件 【已解决】

type TestData struct {
	ID    int64              `json:"id" dc:"ID"`
	Name  string             `json:"name" dc:"Name"`
	File  *ghttp.UploadFile  `json:"file" dc:"File" type:"file"`
	Files *ghttp.UploadFiles `json:"files" dc:"Files" type:"file"`
}
type TestReq struct {
	g.Meta `path:"/v1/admin/user/test" tags:"AdminUser" method:"POST" summary:"Test"`
	ID     int64             `json:"id" dc:"ID"`
	Data   TestData          `json:"data" dc:"Data"`
	File   *ghttp.UploadFile `json:"file" dc:"File" type:"file"`
}

使用 multipart/form-data 上传时

------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[id]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[name]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[description]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[file]"; filename="xxxx.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="file"; filename="xxxxxr.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[files][]"; filename="debug.skk.moe_1732736392647.png"
Content-Type: image/png


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[files][]"; filename="85ee46523adb6a8ee4bf95795c91bef28e24983ed38afbec6789fb5077d75e3f.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="id"

1000
------WebKitFormBoundarypwjjDUNvfZkxxlhH--

【问题描述】
之前使用:

	var (
		request = g.RequestFromCtx(ctx)
	)
	var data = request.GetRequestMap()

获得的结果是扁平化的:

{
  "data": {
    "description": "11111111111111112",
    "id": "11111111111111112",
    "name": "11111111111111112"
  },
  "data[file]": {
    "Filename": "xxxxx.jpg",
  },
  "data[files][]": [
    {
      "Filename": "xxx.png",
    },
    {
      "Filename": "xxx.jpg",
    }
  ],
  "file": {
    "Filename": "xxxx.jpg",
    "Size": 5252553
  },
  "id": "1000"
}

由于没有将 map["data[file]"]map["data"]["file"] 的形式存储,导致最终进行 r.Parse 时无法将文件正确绑定到结构体字段:

File  *ghttp.UploadFile  `json:"file" dc:"File" type:"file"`
Files *ghttp.UploadFiles `json:"files" dc:"Files" type:"file"`

这些字段无论如何都是 nil。

【解决方案】
现在已修复此问题,通过解析嵌套的字段名并构建正确的嵌套Map结构。修复后,GetRequestMap() 返回的结果如下:

{
  "data": {
    "description": "11111111111111112",
    "id": "11111111111111112",
    "name": "11111111111111112",
    "file": {
      "Filename": "xxxxx.jpg",
    },
    "files[]": [
      {
        "Filename": "xxx.png",
      },
      {
        "Filename": "xxx.jpg",
      }
    ]
  },
  "file": {
    "Filename": "xxxx.jpg",
    "Size": 5252553
  },
  "id": "1000"
}

这样,嵌套结构中的文件字段现在可以正确绑定到相应的结构体字段了。这一修复实现了对表单中嵌套文件字段的完整支持。

Please ensure you adhere to every item in this list.

  • The PR title is formatted as follows: <type>[optional scope]: <description> For example, fix(os/gtime): fix time zone issue
    • <type> is mandatory and can be one of fix, feat, build, ci, docs, style, refactor, perf, test, chore
      • fix: Used when a bug has been fixed.
      • feat: Used when a new feature has been added.
      • build: Used for modifications to the project build system, such as changes to dependencies, external interfaces, or upgrading Node version.
      • ci: Used for modifications to continuous integration processes, such as changes to Travis, Jenkins workflow configurations.
      • docs: Used for modifications to documentation, such as changes to README files, API documentation, etc.
      • style: Used for changes to code style, such as adjustments to indentation, spaces, blank lines, etc.
      • refactor: Used for code refactoring, such as changes to code structure, variable names, function names, without altering functionality.
      • perf: Used for performance optimization, such as improving code performance, reducing memory usage, etc.
      • test: Used for modifications to test cases, such as adding, deleting, or modifying test cases for code.
      • chore: Used for modifications to non-business-related code, such as changes to build processes or tool configurations.
    • After <type>, specify the affected package name or scope in parentheses, for example, (os/gtime).
    • The part after the colon uses the verb tense + phrase that completes the blank in
    • Lowercase verb after the colon
    • No trailing period
    • Keep the title as short as possible. ideally under 76 characters or shorter
    • Reference Documentation
  • If there is a corresponding issue, add either Fixes #1234 or Updates #1234
    (the latter if this is not a complete fix) to this comment
  • Delete these instructions once you have read and applied them

提交前请遵守每个事项,感谢!

  • PR 标题格式如下:<类型>[可选 范围]: <描述> 例如 fix(os/gtime): fix time zone issue
    • <类型>是必须的,可以是 fixfeatbuildcidocsstylerefactorperftestchore 中的一个
      • fix: 用于修复了一个 bug
      • feat: 用于新增了一个功能
      • build: 用于修改项目构建系统,例如修改依赖库、外部接口或者升级 Node 版本等
      • ci: 用于修改持续集成流程,例如修改 Travis、Jenkins 等工作流配置
      • docs: 用于修改文档,例如修改 README 文件、API 文档等
      • style: 用于修改代码的样式,例如调整缩进、空格、空行等
      • refactor: 用于重构代码,例如修改代码结构、变量名、函数名等但不修改功能逻辑
      • perf: 用于优化性能,例如提升代码的性能、减少内存占用等
      • test: 用于修改测试用例,例如添加、删除、修改代码的测试用例等
      • chore: 用于对非业务性代码进行修改,例如修改构建流程或者工具配置等
    • <类型>后在括号中填写受影响的包名或范围,例如 (os/gtime)
    • 冒号后使用动词时态 + 短语
    • 冒号后的动词小写
    • 不要有结尾句号
    • 标题尽量保持简短,最好在 76 个字符或更短
    • 参考文档
  • 如果有对应的 issue,请在此评论中添加 Fixes #1234,如果不是完全修复则添加 Updates #1234
  • 应用这些规则后删除所有的说明

当前问题,使用嵌套字段时无法自动绑定到嵌套字段的文件 【已解决】

```
type TestData struct {
	ID    int64              `json:"id" dc:"ID"`
	Name  string             `json:"name" dc:"Name"`
	File  *ghttp.UploadFile  `json:"file" dc:"File" type:"file"`
	Files *ghttp.UploadFiles `json:"files" dc:"Files" type:"file"`
}
type TestReq struct {
	g.Meta `path:"/v1/admin/user/test" tags:"AdminUser" method:"POST" summary:"Test"`
	ID     int64             `json:"id" dc:"ID"`
	Data   TestData          `json:"data" dc:"Data"`
	File   *ghttp.UploadFile `json:"file" dc:"File" type:"file"`
}
```

使用 multipart/form-data 上传时 

```
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[id]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[name]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[description]"

11111111111111112
------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[file]"; filename="xxxx.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="file"; filename="xxxxxr.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[files][]"; filename="debug.skk.moe_1732736392647.png"
Content-Type: image/png


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="data[files][]"; filename="85ee46523adb6a8ee4bf95795c91bef28e24983ed38afbec6789fb5077d75e3f.jpg"
Content-Type: image/jpeg


------WebKitFormBoundarypwjjDUNvfZkxxlhH
Content-Disposition: form-data; name="id"

1000
------WebKitFormBoundarypwjjDUNvfZkxxlhH--
```

【问题描述】
之前使用:
```
	var (
		request = g.RequestFromCtx(ctx)
	)
	var data = request.GetRequestMap()
```
获得的结果是扁平化的:
```
{
  "data": {
    "description": "11111111111111112",
    "id": "11111111111111112",
    "name": "11111111111111112"
  },
  "data[file]": {
    "Filename": "xxxxx.jpg",
  },
  "data[files][]": [
    {
      "Filename": "xxx.png",
    },
    {
      "Filename": "xxx.jpg",
    }
  ],
  "file": {
    "Filename": "xxxx.jpg",
    "Size": 5252553
  },
  "id": "1000"
}
```

由于没有将 `map["data[file]"]` 以 `map["data"]["file"]` 的形式存储,导致最终进行 `r.Parse` 时无法将文件正确绑定到结构体字段:
```
File  *ghttp.UploadFile  `json:"file" dc:"File" type:"file"`
Files *ghttp.UploadFiles `json:"files" dc:"Files" type:"file"`
```
这些字段无论如何都是 nil。

【解决方案】
现在已修复此问题,通过解析嵌套的字段名并构建正确的嵌套Map结构。修复后,`GetRequestMap()` 返回的结果如下:
```
{
  "data": {
    "description": "11111111111111112",
    "id": "11111111111111112",
    "name": "11111111111111112",
    "file": {
      "Filename": "xxxxx.jpg",
    },
    "files[]": [
      {
        "Filename": "xxx.png",
      },
      {
        "Filename": "xxx.jpg",
      }
    ]
  },
  "file": {
    "Filename": "xxxx.jpg",
    "Size": 5252553
  },
  "id": "1000"
}
```

这样,嵌套结构中的文件字段现在可以正确绑定到相应的结构体字段了。这一修复实现了对表单中嵌套文件字段的完整支持。
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