OpenAPI中如何将数组元素作为multipart/form-data独立请求部分?
在OpenAPI的multipart/form-data中拆分数组元素及对象属性为独立请求部分
问题描述
在OpenAPI 3.1中使用multipart/form-data格式时,需要实现两个核心需求:
- 将对象数组的每个元素作为独立的请求部分,而非把整个数组塞进同一个表单字段(当前Swagger生成的curl请求是用逗号分隔JSON对象的形式,所有元素挤在同一个部分)
- 进一步将每个数组元素的对象属性也拆分为独立请求部分,完全避免使用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
相关产品推荐
相关产品推荐

