Pubblica JSON usando le richieste Python


633

Devo inviare un JSON da un client a un server. Sto usando Python 2.7.1 e simplejson. Il client utilizza le richieste. Il server è CherryPy. Posso ottenere un JSON hardcoded dal server (codice non mostrato), ma quando provo a POSTARE un JSON sul server, ottengo "400 Bad Request".

Ecco il mio codice cliente:

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)

Ecco il codice del server.

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())

Qualche idea?


Stavo usando una versione ridotta di un esempio direttamente dalla documentazione .
Charles R

Il mio commento è ancora valido: CherryPy non chiama i __init__metodi di classe con un contentargomento (e non rivendica il link fornito). Nell'esempio dettagliato che hanno, l'utente fornisce il codice che chiama __init__e fornisce gli argomenti, che non abbiamo visto qui, quindi non ho idea dello stato in cui si trova il tuo oggetto quando il tuo # this workscommento è rilevante.
Nick Bastin,

1
Stai chiedendo di vedere la riga in cui viene creata l'istanza?
Charles R

sì, stavo provando ad avviare il tuo esempio per testarlo, e non ero sicuro di come lo stavi istanziando.
Nick Bastin,

Il codice è cambiato Ora lo sto creando senza l'argomento in più. cherrypy.quickstart(Root(), '/', conf).
Charles R

Risposte:


1053

A partire dalla versione 2.4.2 e successive, è possibile utilizzare il parametro "json" nella chiamata in modo da semplificarlo.

>>> 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'}

EDIT: questa funzione è stata aggiunta alla documentazione ufficiale. Puoi visualizzarlo qui: richiede documentazione


114
Non riesco a credere quanto tempo ho perso prima di imbattermi nella tua risposta. I documenti delle richieste devono essere aggiornati, non c'è assolutamente nulla sul jsonparametro. Ho dovuto entrare in Github prima di
vederne la

1
Impostandolo sulla risposta accettata poiché è più idiomatica a partire dalla 2.4.2. Tieni presente che, per un pazzo Unicode, questo potrebbe non funzionare.
Charles R

Ero nei panni di @IAmKale. Questo ha alleviato il mal di testa che avevo con il gateway API di AWS. Richiede i dati POST in formato JSON per impostazione predefinita.
jstudios,

1
Come un pazzo ho provato a usare il parametro data con application / json il tipo di contenuto :(
Operatore illegale

Ho visto un esempio di questo che ha preso l'oggetto dict ed eseguito json.dumps (oggetto) prima di inviarlo. Non farlo ... rovina il tuo JSON. Quanto sopra è perfetto..puoi passargli un oggetto pitone e si trasforma in json perfetto.
MydKnight

376

Si scopre che mi mancavano le informazioni di intestazione. Le seguenti opere:

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)

Buona cattura - Ho visto il tuo application/jsonin GETe in qualche modo mancato che non aveva fornito su richiesta. Potresti anche aver bisogno di assicurarti di restituire qualcosa da POSTo potresti ricevere un 500.
Nick Bastin,

Non sembra essere necessario. Quando stampo r, ottengo <Response [200]>.
Charles R

Come posso recuperare questo json sul lato server?
VaidAbhishek,

r = richieste.get (' localhost: 8080' ) c = risultato contenuto r = contenuto = simplejson.loads (c)
Charles R

1
Il piccolo testa in alto prima di usare json.dumpsqui. Il dataparametro di requestsfunziona bene con i dizionari. Non è necessario convertirlo in una stringa.
Advait S

71

Dalle richieste 2.4.2 ( https://pypi.python.org/pypi/requests ), è supportato il parametro "json". Non è necessario specificare "Tipo di contenuto". Quindi la versione più breve:

requests.post('http://httpbin.org/post', json={'test': 'cheers'})

29

Il modo migliore è :

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
la Content-type: application/jsonè ridondante come json=accenna già che.
Moshe,

1
@Moshe è totalmente d'accordo, ma per richiedere la versione più recente è necessario impostare Elasticsearch sever Content-type
devesh

@Moshe, cosa succede se il tipo di contenuto è text/html; charset=UTF-8. Quindi sopra non funzionerà?
Anu,

2
" Il modo migliore è " non pubblicare risposte ERRATE 3 anni dopo una risposta corretta. -1
CONvid19

3

Funziona perfettamente con Python 3.5+

cliente:

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

server:

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

Quale parametro tra (data / json / files) dovrebbe essere usato, in realtà dipende da un'intestazione di richiesta denominata ContentType (di solito controlla questo tramite gli strumenti di sviluppo del tuo browser),

quando Content-Type è application / x-www-form-urlencoded, il codice dovrebbe essere:

requests.post(url, data=jsonObj)

quando Content-Type è application / json, il codice dovrebbe essere uno dei seguenti:

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

quando Content-Type è multipart / form-data, viene utilizzato per caricare file, quindi il tuo codice dovrebbe essere:

requests.post(url, files=xxxx)

Gesù Cristo, grazie. Mi stavo togliendo i capelli qualche istante fa.
Vahagn Tumanyan,

felice che ti possa aiutare
:)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.