使用Flask测试客户端发送文件会引发“FileStorage不是JSON可序列化的”

时间:2017-09-12 01:53:36

标签: python flask

我正在测试将一些文件发送到Flask路线。但是,我收到错误TypeError: <FileStorage: 'test_photo.jpg' ('image/jpeg')> is not JSON serializable。查看路径'/new-ad/write-details,没有任何东西试图JSON序列化此字段。

video_file = open(test_helpers.get_dummy_file('test_video.mp4'), 'rb')
image_file = open(test_helpers.get_dummy_file('test_photo.jpg'), 'rb')
response = self.app.post(
    '/new-ad/write-details',
    buffered=True,
    content_type='multipart/form-data',
    data={
        'location_id': db.session.query(Location).first().id,
        'category_id': db.session.query(Category).first().id,
        'title': 'test title',
        'body': 'test body',
        'add_video': (video_file, 'test_video.mp4'),
        'add_images': (image_file, 'test_photo.jpg')})
assert response.status_code == 302
assert response.location.partition('?')[0] == 'http://localhost/new-ad/preview'
ad_id = response.location.partition('?')[2].partition('=')[2]
video_file.close()
image_file.close()
Traceback (most recent call last):
  File "tests.py", line 144, in test_ads_creation_routes
    'add_images': (image_file, 'test_photo.jpg')})
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/werkzeug/test.py", line 801, in post
    return self.open(*args, **kw)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/testing.py", line 127, in open
    follow_redirects=follow_redirects)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/werkzeug/test.py", line 764, in open
    response = self.run_wsgi_app(environ, buffered=buffered)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/werkzeug/test.py", line 677, in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/werkzeug/test.py", line 884, in run_wsgi_app
    app_rv = app(environ, start_response)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1615, in full_dispatch_request
    return self.finalize_request(rv)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1632, in finalize_request
    response = self.process_response(response)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 1858, in process_response
    self.save_session(ctx.session, response)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/app.py", line 924, in save_session
    return self.session_interface.save_session(self, session, response)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/sessions.py", line 363, in save_session
    val = self.get_signing_serializer(app).dumps(dict(session))
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/itsdangerous.py", line 565, in dumps
    payload = want_bytes(self.dump_payload(obj))
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/itsdangerous.py", line 847, in dump_payload
    json = super(URLSafeSerializerMixin, self).dump_payload(obj)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/itsdangerous.py", line 550, in dump_payload
    return want_bytes(self.serializer.dumps(obj))
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/sessions.py", line 85, in dumps
    return json.dumps(_tag(value), separators=(',', ':'))
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/json.py", line 123, in dumps
    rv = _json.dumps(obj, **kwargs)
  File "/usr/lib/python3.5/json/__init__.py", line 237, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
  File "/home/dev/Projects/ggp/lib/python3.5/site-packages/flask/json.py", line 80, in default
    return _json.JSONEncoder.default(self, o)
  File "/usr/lib/python3.5/json/encoder.py", line 179, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <FileStorage: 'test_photo.jpg' ('image/jpeg')> is not JSON serializable

2 个答案:

答案 0 :(得分:1)

您展示的代码有效,与您所显示的错误无关。该错误表示您正在尝试将文件对象添加到session。这是一个坏主意。

会话是一个cookie,它不仅大小有限,而且随着客户端发出的每个请求被发送到服务器。向其添加整个文件会无缘无故地大大增加网络流量。

如果您确实需要会话中的文件或任何JSON响应,请在磁盘上添加对其路径的引用,而不是数据本身。然后,当您需要文件发出请求单独提供文件时。 Web服务器非常擅长提供文件。

return jsonify({'video': '/path/to/video.mp4'})

如果出于某种原因,您确实需要将文件数据添加到JSON有效负载(但实际上,您不是),请先使用base64对其进行序列化。这在空间和时间上效率低下,因此将其视为最后的手段。

from base64 import b64encode
return jsonify({'video': b64encode(video.read())})

答案 1 :(得分:0)

如果没有您的测试代码,这很容易重现。

f = open('{path_to_file}', 'rb')
print(type(f))

import json
json.dumps(f)

json.dumps将抛出异常,因为文件对象本身并不是JSON可序列化的。

Flask正在尝试在发送内容之前序列化内容,并且失败。如果要将文件内容发送到服务器,则需要读入内容并发送字节。

with open('{path_to_file}', 'rb') as f:
    contents = f.read()