You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenAPI中如何将数组元素作为multipart/form-data独立请求部分?

在OpenAPI的multipart/form-data中拆分数组元素及对象属性为独立请求部分

问题描述

在OpenAPI 3.1中使用multipart/form-data格式时,需要实现两个核心需求:

  1. 将对象数组的每个元素作为独立的请求部分,而非把整个数组塞进同一个表单字段(当前Swagger生成的curl请求是用逗号分隔JSON对象的形式,所有元素挤在同一个部分)
  2. 进一步将每个数组元素的对象属性也拆分为独立请求部分,完全避免使用JSON传输数据

当前使用的OpenAPI配置如下:

paths:
  /grammars/test1:
    summary: Test1
    post:
      operationId: test1
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                grammarList:
                  type: array
                  items:
                    type: object
                    properties:
                      name: 
                        type: string
                      type:
                        enum:
                          - uri
                          - inline
                      grammar:
                        type: string
            encoding: 
              explode: true

根据OpenAPI 3.1规范:

In a multipart/form-data request body, each schema property, or each element of a schema array property, takes a section in the payload with an internal header as defined by [RFC7578].

但实际测试中,Swagger生成的curl请求仍将所有数组元素合并在同一个grammarList部分:

curl -X 'POST' \
  'http://localhost:8000/grammars/test1' \
  -H 'accept: applicaton/xml' \
  -H 'Content-Type: multipart/form-data' \
  -F 'grammarList={
  "name": "string",
  "type": "uri",
  "grammar": "string"
},{
  "name": "string1",
  "type": "uri",
  "grammar": "string"
}'

接收端收到的请求内容显示所有数组元素处于同一表单部分:

POST /grammars/test1 HTTP/1.1
Host: localhost:8000
User-Agent: curl/7.87.0
accept: applicaton/xml
Content-Length: 272
Content-Type: multipart/form-data; boundary=------------------------32ea353bafc67a64

--------------------------32ea353bafc67a64
Content-Disposition: form-data; name="grammarList"

{
  "name": "string",
  "type": "uri",
  "grammar": "string"
},{
  "name": "string1",
  "type": "uri",
  "grammar": "string"
}
--------------------------32ea353bafc67a64--

解决方案

1. 将数组元素拆分为独立请求部分

需要针对数组字段单独配置编码规则,而非在encoding根节点全局设置explode: true。修改后的OpenAPI配置如下:

paths:
  /grammars/test1:
    summary: Test1
    post:
      operationId: test1
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                grammarList:
                  type: array
                  items:
                    type: object
                    properties:
                      name: 
                        type: string
                      type:
                        enum:
                          - uri
                          - inline
                      grammar:
                        type: string
            encoding:
              grammarList:  # 针对数组字段单独配置编码
                style: form
                explode: true

调整后,每个数组元素会作为独立的grammarList表单部分发送,请求结构类似:

POST /grammars/test1 HTTP/1.1
Host: localhost:8000
User-Agent: curl/7.87.0
accept: applicaton/xml
Content-Type: multipart/form-data; boundary=------------------------xxxxxx

--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList"
Content-Type: application/json

{"name":"string","type":"uri","grammar":"string"}
--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList"
Content-Type: application/json

{"name":"string1","type":"uri","grammar":"string1"}
--------------------------xxxxxx--

2. 将数组元素的属性拆分为独立请求部分

如果要完全避免JSON,把每个对象的属性也拆成单独的表单字段,需要使用索引式字段命名(如grammarList[0].name),并调整schema结构或客户端请求构造逻辑。

方式一:显式定义索引字段(适用于固定长度数组)

paths:
  /grammars/test1:
    summary: Test1
    post:
      operationId: test1
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                grammarList[0].name:
                  type: string
                grammarList[0].type:
                  enum: [uri, inline]
                grammarList[0].grammar:
                  type: string
                grammarList[1].name:
                  type: string
                grammarList[1].type:
                  enum: [uri, inline]
                grammarList[1].grammar:
                  type: string

对应的请求结构为:

--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList[0].name"

string
--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList[0].type"

uri
--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList[0].grammar"

string
--------------------------xxxxxx
Content-Disposition: form-data; name="grammarList[1].name"

string1
--------------------------xxxxxx--

方式二:动态构造请求(适用于可变长度数组)

OpenAPI 3.1对这种嵌套属性的自动拆分支持有限,部分工具无法自动生成示例,需要客户端手动构造符合索引命名规则的表单字段,服务端按照对应规则解析即可。

关键注意事项

  • explode: true必须针对具体数组字段配置,全局配置不会生效到数组元素上
  • 部分OpenAPI工具(如Swagger UI)对multipart数组拆分的支持存在滞后,可直接用以下curl命令测试数组元素拆分效果:
    curl -X POST http://localhost:8000/grammars/test1 \
      -H "accept: application/xml" \
      -H "Content-Type: multipart/form-data" \
      -F "grammarList={\"name\":\"string\",\"type\":\"uri\",\"grammar\":\"string\"}" \
      -F "grammarList={\"name\":\"string1\",\"type\":\"uri\",\"grammar\":\"string1\"}"
    
  • 若要完全避免JSON,必须和服务端约定好索引式字段命名规则,客户端按规则拆分属性为独立表单字段

内容的提问来源于stack exchange,提问作者user8729669

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:35:26