使用python将json和文件发送到烧瓶

时间:2017-12-06 16:37:15

标签: json file post flask request

我有这个问题,我试图在一个函数中向一个烧瓶API发送/接收一些文件和JSON。

在我的客户(发件人)上我有:

#my json to be sent 
datas = {'var1' : 'var1','var2'  : 'var2',}
#my file to be sent 
local_file_to_send = 'user_picture.jpg'
url = "http://10.100.2.6:80/customerupdate"
headers = {'Content-type': 'multipart/form-data'}
files = {'document': open(local_file_to_send, 'rb')}
r = requests.post(url, files=files, data=datas, headers=headers)

在我的Flask服务器上,我有:

class OPERATIONS(Resource):
        @app.route('/',methods=['GET'])
        def hello_world():
            return 'Hello World!'

        @app.route('/customerupdate',methods=['GET','POST'])
        def customerupdate():
            event_data_2 = json.loads(request.get_data().decode('utf-8'))
            print event_data_2

我有这条错误消息告诉我数据实际上不是json格式,也不是utf8格式。如果我打印“get_data”的内容而不尝试解码它会显示一些二进制字符..

我的客户端上读取json并在本地写入文件的语法是什么?

4 个答案:

答案 0 :(得分:3)

我建议将JSON和文件作为multipart表单的一部分发送。在这种情况下,您将从服务器上的request.files读取它们。 (一个警告:我使用Python 3测试了所有示例,请求2.18.4和Flask 0.12.2 - 您可能需要更改代码以匹配您的环境。)

https://stackoverflow.com/a/35940980/2415176(以及http://docs.python-requests.org/en/latest/user/advanced/#post-multiple-multipart-encoded-files处的Flask文档),您无需指定标题或任何内容。您可以让requests为您处理:

import json
import requests

# Ton to be sent
datas = {'var1' : 'var1','var2'  : 'var2',}

#my file to be sent
local_file_to_send = 'tmpfile.txt'
with open(local_file_to_send, 'w') as f:
    f.write('I am a file\n')

url = "http://127.0.0.1:3000/customerupdate"

files = [
    ('document', (local_file_to_send, open(local_file_to_send, 'rb'), 'application/octet')),
    ('datas', ('datas', json.dumps(datas), 'application/json')),
]

r = requests.post(url, files=files)
print(str(r.content, 'utf-8'))

然后在服务器上,您可以阅读request.files(请参阅http://flask.pocoo.org/docs/0.12/api/#flask.Request.files,但请注意,request.files的工作方式略有不同,请参阅https://stackoverflow.com/a/11817318/2415176):

import json                                                     

from flask import Flask, request                                

app = Flask(__name__)                                           

@app.route('/',methods=['GET'])                                 
def hello_world():                                              
    return 'Hello World!'                                       

@app.route('/customerupdate',methods=['GET','POST'])            
def customerupdate():                                           
    posted_file = str(request.files['document'].read(), 'utf-8')
    posted_data = json.load(request.files['datas'])             
    print(posted_file)                                          
    print(posted_data)                                          
    return '{}\n{}\n'.format(posted_file, posted_data)          

答案 1 :(得分:3)

感谢Craig的回答,我找到了解决方案。我将发布两个代码(客户端和服务器)以帮助以备将来使用。 CLient服务器正在以"形式上传文件和Json。烧瓶的特点。然后一些和一些dict使Payload更清晰(我知道这是丑陋的方式,但这是最好的学者方法)

客户端 方面:

datas = {'CurrentMail': "AA", 'STRUserUUID1': "BB", 'FirstName': "ZZ",     'LastName': "ZZ",  'EE': "RR", 'JobRole': "TT"  }

#sending user infos to app server using python "requests"
url = "http://10.100.2.6:80/customerupdate"
def send_request():
    payload = datas
    local_file_to_send = 'user_picture.jpg' 
    files = {
     'json': (None, json.dumps(payload), 'application/json'),
     'file': (os.path.basename(local_file_to_send), open(local_file_to_send, 'rb'), 'application/octet-stream')
    }
    r = requests.post(url, files=files)

send_request()

Flask服务器 方面:

import sys, os, logging, time, datetime, json, uuid, requests, ast
from flask import Flask, request , render_template
from werkzeug import secure_filename
from werkzeug.datastructures import ImmutableMultiDict
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)
app.debug = True

class OPERATIONS(Resource):
        @app.route('/',methods=['GET'])
        def hello_world():
            return 'Hello World!'

        @app.route('/customerupdate',methods=['GET','POST'])
        def customerupdate():
            print "************DEBUG 1 ***********"
            RequestValues = request.values
            print RequestValues
            print "************DEBUG 2 ***********"
            RequestForm = request.form
            print RequestForm
            print "************DEBUG 2-1 ***********"
            so = RequestForm
            json_of_metadatas = so.to_dict(flat=False)
            print json_of_metadatas
            print "************DEBUG 2-2 ***********"
            MetdatasFromJSON = json_of_metadatas['json']
            print MetdatasFromJSON          
            print "************DEBUG 2-3 ***********"
            MetdatasFromJSON0 = MetdatasFromJSON[0]
            print MetdatasFromJSON0
            print "************DEBUG 3-5 ***********"
            strMetdatasFromJSON0 = str(MetdatasFromJSON0)
            MetdatasDICT = ast.literal_eval(strMetdatasFromJSON0)
            print MetdatasDICT
            print "************DEBUG 3-5 ***********"
            for key in MetdatasDICT :
                print "key: %s , value: %s" % (key, MetdatasDICT[key])
            print "************DEBUG 4 ***********"
            f = request.files['file']
            f.save(secure_filename(f.filename))
            print "FILE SAVED LOCALY"
            return 'JSON of customer posted'

答案 2 :(得分:2)

如果这不在生产中,那么有一种比将json绑定到文件中更简单的方法,将json数据作为参数值发送,而不是将其绑定到json中。

datas = {data: {'var1' : 'var1','var2'  : 'var2}}
url = "http://10.100.2.6:80/customerupdate"
files = {'document': open(local_file_to_send, 'rb')}
headers = {'Content-type': 'application/json'}
r = requests.post(url, files=files, params=datas, headers=headers)

并且在flask服务器中,数据和文件的接收方式为:

image = request.files.get('image')
data = request.args.get('data')

答案 3 :(得分:0)

我能够通过 TestClient post 在 data 属性中发送 json 和文件,如下所示:

with self.app.test_client() as c:
data = {'here': 'is', 'some': 'data' }
data={
        'file': filename, open(filename, 'rb'), "image/jpeg"),
        'json': json.dumps(data)}
rv = c.post(url, data=data)

可以从请求表单加载服务器端json:

json_data = json.loads(request.form["json"])

可以从文件中加载文件

file = request.files["file"]

通过这种方式可以清楚地区分文件和其他数据。

我在此处找到了数据的外观:https://werkzeug.palletsprojects.com/en/1.0.x/test/#werkzeug.test.EnvironBuilder