Опубликовать JSON с использованием запросов Python

633

Мне нужно отправить JSON от клиента к серверу. Я использую Python 2.7.1 и simplejson. Клиент использует запросы. Сервер является CherryPy. Я могу получить жестко закодированный JSON с сервера (код не показан), но когда я пытаюсь отправить JSON на сервер, я получаю «400 Bad Request».

Вот мой код клиента:

data = {'sender':   'Alice',
    'receiver': 'Bob',
    'message':  'We did it!'}
data_json = simplejson.dumps(data)
payload = {'json_payload': data_json}
r = requests.post("http://localhost:8080", data=payload)

Вот код сервера.

class Root(object):

    def __init__(self, content):
        self.content = content
        print self.content  # this works

    exposed = True

    def GET(self):
        cherrypy.response.headers['Content-Type'] = 'application/json'
        return simplejson.dumps(self.content)

    def POST(self):
        self.content = simplejson.loads(cherrypy.request.body.read())

Любые идеи?

Чарльз Р
источник
Я использовал урезанную версию примера прямо из документации .
Чарльз R
Мой комментарий остается в силе - CherryPy не вызывает __init__методы класса с contentаргументом (и не претендует на указанную вами ссылку). В подробном примере, который у них есть, пользователь предоставляет код, который вызывает __init__и предоставляет аргументы, которых мы здесь не видели, поэтому я понятия не имею, в каком состоянии находится ваш объект, когда ваш # this worksкомментарий актуален.
Ник Бастин
1
Вы просите увидеть строку, где создается экземпляр?
Чарльз Р
да, я пытался запустить твой пример, чтобы проверить его, и я не был уверен, как ты его создавал.
Ник Бастин
Код изменился. Я сейчас создаю это без лишних аргументов. cherrypy.quickstart(Root(), '/', conf),
Чарльз Р

Ответы:

1053

Начиная с версии 2.4.2 запросов, вы можете альтернативно использовать параметр json в вызове, что упрощает его.

>>> import requests
>>> r = requests.post('http://httpbin.org/post', json={"key": "value"})
>>> r.status_code
200
>>> r.json()
{'args': {},
 'data': '{"key": "value"}',
 'files': {},
 'form': {},
 'headers': {'Accept': '*/*',
             'Accept-Encoding': 'gzip, deflate',
             'Connection': 'close',
             'Content-Length': '16',
             'Content-Type': 'application/json',
             'Host': 'httpbin.org',
             'User-Agent': 'python-requests/2.4.3 CPython/3.4.0',
             'X-Request-Id': 'xx-xx-xx'},
 'json': {'key': 'value'},
 'origin': 'x.x.x.x',
 'url': 'http://httpbin.org/post'}

РЕДАКТИРОВАТЬ: Эта функция была добавлена ​​в официальную документацию. Вы можете просмотреть его здесь: Запрос документации

Зеянг Лин
источник
114
Я не могу поверить, сколько времени я потратил впустую, прежде чем наткнуться на ваш ответ. Документы с запросами должны быть обновлены, в параметре нет абсолютно ничего json. Мне пришлось зайти в Github, прежде чем я увидел упоминания об этом: github.com/kennethreitz/requests/blob/…
IAmKale
1
Установка этого к принятому ответу, так как это более идиоматично с 2.4.2. Имейте в виду, для сумасшедшего юникода это может не сработать.
Чарльз Р
Я был в той же обуви, что и @IAmKale. Это избавило меня от головной боли, связанной с API-шлюзом AWS. По умолчанию требуются данные POST в формате JSON.
jstudios
1
Как дурак, я пытался использовать параметр data с application / json для типа контента :(
Illegal Operator
Я видел пример этого, который взял объект dict и выполнил json.dumps (объект) перед отправкой. Не делай этого ... это портит твой JSON. Вышесказанное идеально ... Вы можете передать ему объект Python, и он превратится в идеальный JSON.
MydKnight
376

Оказывается, мне не хватало информации заголовка. Следующие работы:

url = "http://localhost:8080"
data = {'sender': 'Alice', 'receiver': 'Bob', 'message': 'We did it!'}
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
r = requests.post(url, data=json.dumps(data), headers=headers)
Чарльз Р
источник
Хороший улов - Я видел вашу application/jsonин GETи как - то пропустил , что вы не предоставили его по требованию. Вам также может потребоваться убедиться, что вы что-то возвращаете POSTили можете получить 500.
Ник Бастин
Кажется, не нужно. Когда я печатаю r, я получаю <Response [200]>.
Чарльз Р
Как мне получить этот JSON на стороне сервера?
Вайд Абхишек
r = orders.get (' localhost: 8080' ) c = r.content result = simplejson.loads (c)
Чарльз R
1
Маленькие головы перед использованием json.dumpsздесь. dataПараметр requestsпрекрасно работает со словарями. Нет необходимости конвертировать в строку.
Advait S
71

Из запросов 2.4.2 ( https://pypi.python.org/pypi/requests ) поддерживается параметр "json". Не нужно указывать «Content-Type». Итак, более короткая версия:

requests.post('http://httpbin.org/post', json={'test': 'cheers'})
ЗЗЫ
источник
29

Лучший способ :

url = "http://xxx.xxxx.xx"

datas = {"cardno":"6248889874650987","systemIdentify":"s08","sourceChannel": 12}

headers = {'Content-type': 'application/json'}

rsp = requests.post(url, json=datas, headers=headers)
Эллен
источник
18
Content-type: application/jsonявляется излишним , поскольку json=уже намекает , что.
Моше
1
@ Моше полностью согласен, но для запроса более новой версии Elasticsearch sever требуется установить Content-type
devesh
@Moshe, что делать, если тип контента text/html; charset=UTF-8. Тогда выше не будет работать?
Ану
2
« Лучший способ» - не публиковать НЕПРАВИЛЬНЫЕ ответы через 3 года после правильного ответа. -1
CONvid19
3

Отлично работает с питоном 3.5+

клиент:

import requests
data = {'sender':   'Alice',
    'receiver': 'Bob',
    'message':  'We did it!'}
r = requests.post("http://localhost:8080", json={'json_payload': data})

сервер:

class Root(object):

    def __init__(self, content):
        self.content = content
        print self.content  # this works

    exposed = True

    def GET(self):
        cherrypy.response.headers['Content-Type'] = 'application/json'
        return simplejson.dumps(self.content)

    @cherrypy.tools.json_in()
    @cherrypy.tools.json_out()
    def POST(self):
        self.content = cherrypy.request.json
        return {'status': 'success', 'message': 'updated'}
Рухил Джайсвал
источник
3

Какой параметр между (data / json / files) следует использовать, на самом деле это зависит от заголовка запроса с именем ContentType (обычно проверяйте это с помощью инструментов разработчика вашего браузера),

когда Content-Type является application / x-www-form-urlencoded, код должен быть:

requests.post(url, data=jsonObj)

когда Content-Type - это application / json, ваш код должен быть одним из следующих:

requests.post(url, json=jsonObj)
requests.post(url, data=jsonstr, headers={"Content-Type":"application/json"})

когда Content-Type является multipart / form-data, он используется для загрузки файлов, поэтому ваш код должен быть:

requests.post(url, files=xxxx)
Сяомин
источник
Иисус Христос, спасибо. Я вычесывал свои волосы несколько минут назад.
Ваагн Туманян
рад, что может помочь вам
:)