我使用flask和flask-restplus为我的应用程序生成了一个上传api端点。一切似乎工作正常,但收到的文件数据为空,然后保存的文件为空。
这是我的代码
upload_parser = reqparse.RequestParser()
upload_parser.add_argument('data', location='files', type=FileStorage, required=True)
...
@ns.route('/upload')
class Upload(Resource):
@api.expect(upload_parser)
def post(self):
args = upload_parser.parse_args()
uploaded_file = args['data'] # This is FileStorage instance
scan_for_virus(uploaded_file) # This function raised error if a virus are found
destination = current_app.config.get('UPLOAD_DATA_FOLDER')
if not os.path.exists(destination):
os.makedirs(destination)
temp_filename = os.path.join(destination, str(uuid.uuid4()))
print uploaded_file # print "<FileStorage: u'IMG-20190129-WA0001.jpg' ('image/jpeg')>" seems correct
print uploaded_file.stream # print "<tempfile.SpooledTemporaryFile instance at 0x104b1c3f8>}"
print uploaded_file.content_length # print "0" ..... but my orignal file size is 4352436 bytes
uploaded_file.save(temp_filename) # create the file with the correct path, but this new file is empty.
return {'url': 'upload://{0}'.format(os.path.basename(temp_filename))}, 202
我使用swagger接口(由restplus框架生成)来上传文件。发送的请求是:
curl -X POST "http://localhost:8888/api/upload" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "data=@my_file.pdf;type=application/pdf"
您对解决我的问题有什么建议吗?我需要在烧瓶配置中指定一些特殊的内容吗? 谢谢您的帮助
雷诺(Renaud)
答案 0 :(得分:0)
好,我找到了问题。...问题出在我的scan_for_virus函数中:
def scan_for_virus(uploaded_file):
try:
cd = pyclamd.ClamdUnixSocket(current_app.config.get('CLAMAV_SOCKET_FILE', '/tmp/clamd.socket'))
cd.ping()
except pyclamd.ConnectionError as ce:
log.error("Unable to connect to Clamd :: "+str(ce))
abort(500, str(ce))
scan_result = cd.scan_stream(uploaded_file.stream)
if scan_result is not None: # In this case ClamAV found a virus !
log.warning("Virus found into {0} :: {1}".format(uploaded_file.filename, scan_result['stream'][1]))
abort(502, "Virus found !", detail=scan_result['stream'][1])
如您所见,scan_stream使用uploaded_file.stream
属性读取upload_file内容。但是FileStorage.save()
函数也使用stream属性,因此我需要在第一次读取后重置流:
....
scan_result = cd.scan_stream(uploaded_file.stream)
uploaded_file.stream.seek(0)
....
只要这样做,它就会按预期工作。