Opublikuj JSON za pomocą Pythona


632

Muszę wysłać JSON z klienta na serwer. Używam Python 2.7.1 i simplejson. Klient korzysta z żądań. Serwer to CherryPy. Mogę pobrać z serwera zakodowany na stałe kod JSON (kod nie pokazano), ale gdy próbuję wysłać JSON na serwer, otrzymuję komunikat „400 Bad Request”.

Oto mój kod klienta:

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)

Oto kod serwera.

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

Jakieś pomysły?


Użyłem uproszczonej wersji przykładu prosto z dokumentacji .
Charles R

Mój komentarz nadal trwa - CherryPy nie wywołuje __init__metod klasowych z contentargumentem (i nie twierdzi, że w podanym linku). W szczegółowym przykładzie, jaki mają, użytkownik dostarcza kod, który wywołuje __init__i podaje argumenty, których nie widzieliśmy tutaj, więc nie mam pojęcia, w jakim stanie jest twój obiekt, gdy # this workskomentarz jest odpowiedni.
Nick Bastin

1
Czy chcesz wyświetlić wiersz, w którym tworzona jest instancja?
Charles R

tak, próbowałem uruchomić twój przykład, aby go przetestować, i nie byłem pewien, jak go tworzysz.
Nick Bastin

Kod się zmienił. Teraz tworzę go bez dodatkowego argumentu. cherrypy.quickstart(Root(), '/', conf).
Charles R

Odpowiedzi:


1051

Począwszy od wersji 2.4.2 Żądań, można alternatywnie użyć parametru „json” w wywołaniu, co upraszcza.

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

EDYCJA: Ta funkcja została dodana do oficjalnej dokumentacji. Możesz go zobaczyć tutaj: Żąda dokumentacji


114
Nie mogę uwierzyć, ile czasu zmarnowałem, zanim natknąłem się na twoją odpowiedź. Dokumenty żądań wymagają aktualizacji, parametr nie ma absolutnie nic json. Musiałem wejść do Github, zanim zobaczyłem jakąkolwiek wzmiankę: github.com/kennethreitz/requests/blob/…
IAmKale

1
Ustawienie na akceptowaną odpowiedź, ponieważ jest to bardziej idiomatyczne od 2.4.2. Pamiętaj, że w przypadku szalonego Unicode może to nie działać.
Charles R

Byłem w tych samych butach, co @IAmKale. Zmniejszyło to dość ból głowy związany z bramą API AWS. Domyślnie wymaga danych POST w formacie JSON.
jstudios

1
Jak głupiec próbowałem użyć parametru danych w aplikacji / json typ zawartości :(
Nielegalny operator

Widziałem przykład tego, który wziął obiekt dict i wykonał json.dumps (obiekt) przed wysłaniem. Nie rób tego ... to psuje twój JSON. Powyższe jest idealne .. możesz przekazać mu obiekt python i zamienia się on w doskonały json.
MydKnight

376

Okazuje się, że brakowało mi informacji nagłówka. Następujące prace:

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)

Dobry chwyt - Widziałem twoje application/jsonin GETi jakoś brakowało, że nie dostarczyła je na żądanie. Może być również konieczne upewnienie się, że coś zwrócisz POSTlub możesz dostać 500.
Nick Bastin

Nie wydaje się to konieczne. Kiedy drukuję r, dostaję <Response [200]>.
Charles R

Jak pobrać ten Json po stronie serwera?
VaidAbhishek

r = requests.get (' localhost: 8080' ) c = r.content result = simplejson.loads (c)
Charles R

1
Małe głowy przed użyciem json.dumpstutaj. dataParametr requestsdziała dobrze ze słownikami. Nie ma potrzeby konwersji na ciąg.
Advait S


29

Lepszym sposobem jest :

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/jsonjest zbędny, ponieważ json=już sugeruje, że.
Mosze

1
@Moshe całkowicie się zgadza, ale aby poprosić o nowszą wersję, elasticsearch wymaga ustawienia Content-type
devesh

@Moshe, Co jeśli typ zawartości to text/html; charset=UTF-8. Czy powyższe nie zadziała?
Anu

2
Lepszym sposobem jest ” nie publikowanie NIEPRAWIDŁOWYCH odpowiedzi 3 lata po prawidłowej odpowiedzi. -1
CONvid19,

3

Działa idealnie z python 3.5+

klient:

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

serwer:

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

Który parametr między (dane / json / pliki) powinien zostać użyty, to zależy od nagłówka żądania o nazwie ContentType (zwykle sprawdź to za pomocą narzędzi programistycznych w przeglądarce),

gdy typem treści jest application / x-www-form-urlencoded, kod powinien być:

requests.post(url, data=jsonObj)

gdy typem treści jest application / json, twój kod powinien być jednym z poniższych:

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

gdy typem treści jest wieloczęściowy / formularz-dane, służy on do przesyłania plików, więc kod powinien być:

requests.post(url, files=xxxx)

Jezu Chryste, dziękuję. Kilka chwil temu odsuwałam włosy.
Vahagn Tumanyan

cieszę się, że może ci pomóc
:)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.