spring-boot 接收form表单 多文件加多字段数据(postman在form-data格式下传数组和集合)
Posted 卿先生的学习之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-boot 接收form表单 多文件加多字段数据(postman在form-data格式下传数组和集合)相关的知识,希望对你有一定的参考价值。
前言
该博客多用于记录自己的问题
在写项目的时候遇到这种业务情况:
需要保存整个页面的数据,数据包含多个字段信息和多个文件
结合网上的处理思路,我最终实现了这种业务需求并整理一下
前端单独提交字段和文件比较方便简单,本人不太了解前端,既然前端说要用form表单同时传字段和文件,那么我就以这样的方式去研究怎么去同时接收
先看一下最终结果
其中遇到的一下问题
1.前端的数据格式是 multipart/form-data,不再是json格式,后端接收就不能加注解@RequestBody
如:
会报错,不支持这个方式
"msg": "Content type 'multipart/form-data;boundary=--------------------------958211735005905900137890;charset=UTF-8' not supported",
2. 所以前端就不能以对象的方式传数据,我不了解是否有其他解决方法,目前我的前端就是以键值对的方式给我数据,以postman为例
数据格式form-data,其中files是文件,其余是一个对象的字段,需求是多个文件,所以是以数组的方式接收
注意的是用postman以form-data格式传数组 按上图所示即可
3.同理,前端用form表单传文件数组时也遇到了问题,开始是将文件放入了名叫files数组一起传,但是后台接收不到,我猜测是没按键值对方式的原因,
最终解决是,文件名"name"为files,value值为不同的文件,如同postman的格式
4.其中,我的业务需求里,在对象中包含集合,看网上一些人说在上面这个传输格式下,不用注解@RequestBody,不会将集合自动装配到对象中,我用postman实验了一下,可以自动装配到对象中
需要注意的是:如何在form-data格式下传集合
如:
解析多部分/表单数据,从请求后接收
【中文标题】解析多部分/表单数据,从请求后接收【英文标题】:parse multipart/form-data, received from requests post 【发布时间】:2016-01-26 22:37:48 【问题描述】:我正在使用请求库编写 Web 服务客户端。我在包含文件和文本 json 的 multipart/form-data 中获取数据。我不知道如何解析它。是否有合适的库来解析 python 中的 multipart/form-data 格式,还是我应该自己编写解析器?
我的代码:
data =
"prototypeModel" :('prototypeModel', open(prototypeModel, 'rb'), 'application/octet-stream', 'Expires': '0'),
"mfcc_1" : ('mfcc', open(mfcc_1, 'rb'), 'application/octet-stream', 'Expires': '0'),
"mfcc_2" : ('mfcc', open(mfcc_2, 'rb'), 'application/octet-stream', 'Expires': '0'),
"mfcc_3" : ('mfcc', open(mfcc_3, 'rb'), 'application/octet-stream', 'Expires': '0'),
print( '---------------------- start enroll ----------------------')
testEnrollResponse = requests.post(server+sessionID, files = data, json = declaredParameters)
b'\r\n--c00750d1-8ce4-4d29-8390-b50bf02a92cc\r\n内容配置: 表格数据; name="playbackHash"\r\n内容类型: 应用程序/八位字节流\r\n\r\n\x16\x00\x00\x00\x00\x00\x00\x00serialization::archive\n\x00\x04\x08\x04 …… x00\x00R\x94\x9bp\x8c\x00\r\n--c00750d1-8ce4-4d29-8390-b50bf02a92cc\r\n内容配置: 表格数据; name="usersMFCC"\r\n内容类型: 应用程序/八位字节流\r\n\r\n\x16\x00\x00\x00\x00\x00\x00\x00serialization::archive\n\x00\x04\x08\x04\x08\x01\x00\x00 \x00\x00\x00\x00\x00\x00\xf8\x16\x00\x00\x00\x00\x00\x00u\xbd\xb4/\xda1\xea\xbf\x0f\xed\xa2 x80\xd9\x95Yxn\xd0?\r\n--c00750d1-8ce4-4d29-8390-b50bf02a92cc\r\n内容-处置: 表格数据; name="scoreAndStatus"\r\nContent-Type: application/json; charset=utf-8\r\n\r\n"lexLikelihood":1.544479046897232,"overallScore":-nan,"playbackLikelihood":-inf,"status":"errorCode":0,"errorMessage":" "\r\n--c00750d1-8ce4-4d29-8390-b50bf02a92cc--\r\n'
我用“.....”替换了更多的二进制数据
【问题讨论】:
向我们展示您收到的回复。 【参考方案1】:如果您收到 multipart/form-data
响应,您可以使用 requests-toolbelt
库解析它,如下所示:
$ pip install requests-toolbelt
安装后
from requests_toolbelt.multipart import decoder
testEnrollResponse = requests.post(...)
multipart_data = decoder.MultipartDecoder.from_response(testEnrollResponse)
for part in multipart_data.parts:
print(part.content) # Alternatively, part.text if you want unicode
print(part.headers)
【讨论】:
【参考方案2】:Flask 的代码示例,使用 https://github.com/defnull/multipart
import multipart as mp
from multipart import tob
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
@app.route('/', methods=["GET","POST"])
def index():
...
elif flask.request.method == "POST":
data = flask.request.data
s = data.split("\r")[0][2:]
p = mp.MultipartParser(BytesIO(tob(data)),s)
blob = p.parts()[0].value
f = open("file.bin","wb")
f.write(blob.encode("latin-1"))
f.close()
【讨论】:
它是关于请求客户端而不是烧瓶服务器 是的,您可以将我的代码改编为 Web 服务客户端。我的代码没有使用 python-requests 模块。它正在工作。 但这与问题无关。 它有正确的信息,但它没有以任何方式回答问题。 这有有用的信息,事实上,当我试图为服务器端找到类似的东西时,这篇文章就出现了。即使问题是双向的,它表示接收请求,可能来自客户端。【参考方案3】:下面是解析多部分数据的working example。您可以在交互式 python 提示符下尝试一下。
import email
msg = email.message_from_string('''\
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=" XXXX"
-- XXXX
Content-Type: text/plain
-- XXXX
Content-Type: text/plain
-- XXXX--
''')
msg.is_multipart()
一旦您知道它在您的系统上运行,您就可以根据 POST 数据构建您自己的电子邮件消息并以相同的方式对其进行解析。如果您将原始post body 作为字符串,则可以在请求标头中找到其余必要信息。为了清楚起见,我在此处添加了缩进,您不应该在块字符串中有多余的缩进。
epost_data = '''\
MIME-Version: 1.0
Content-Type: %s
%s''' % (self.headers['content-type'], post_data)
msg = email.message_from_string(post_data)
if msg.is_multipart():
for part in msg.get_payload():
name = part.get_param('name', header='content-disposition')
filename = part.get_param('filename', header='content-disposition')
# print 'name %s' % name # "always" there
# print 'filename %s' % filename # only there for files...
payload = part.get_payload(decode=True)
print payload[:100] # output first 100 characters
第一个%s
将替换为内容类型,第二个将替换为post_data
。然后,您可以将有效负载写入文件等。
请小心考虑保存文件的安全隐患。您可能无法信任发布的文件名,它可能以 ../../filename.sh
开头,例如在某些 Web 服务器上,因此如果您尝试编写 /my-folder/../../filename.sh
,攻击者可能会将恶意文件放置在您所在位置之外试图存储文件。还建议在信任文件本身之前对文件作为允许的类型进行强验证。您不想让攻击者覆盖您系统上的任何文件。
【讨论】:
以上是关于spring-boot 接收form表单 多文件加多字段数据(postman在form-data格式下传数组和集合)的主要内容,如果未能解决你的问题,请参考以下文章
从 multipart/form-data 接收带有 servicestack 的文件
优雅的方式来校验spring-boot的form表单参数和json的body参数合法性验证方式
HttpMediaTypeNotSupportedException:不支持内容类型“应用程序/表单数据”spring-boot