2013-03-28 9 views
11

Mi sono imbattuto in questo problema quando giocavo con un'API esterna. Inviavo i miei dati del corpo come un dizionario dritto nella richiesta e stavo 400 errori:Perché il corpo della richiesta POST HTTP deve essere JSON enconded in Python?

data = { 
    "someParamRange": { 
    "to": 1000, 
    "from": 100 
    }, 
    "anotherParamRange": { 
    "to": True, 
    "from": False 
    } 
} 

Quando ho aggiunto un involucro json.dumps, funziona:

data = json.dumps({ 
    "someParamRange": { 
    "to": 1000, 
    "from": 100 
    }, 
    "anotherParamRange": { 
    "to": True, 
    "from": False 
    } 
}) 

che faccio non del tutto capire perché questo è necessario, poiché i dizionari e gli oggetti JSON sono sintatticamente identici. Qualcuno può aiutarmi a capire cosa sta succedendo dietro le quinte qui?

Per completezza, ecco le mie intestazioni:

headers = {'API-KEY': 'blerg', 'Accept-Encoding': 'UTF-8', 'Content-Type': 'application/json', 'Accept': '*/*', 'username': 'user', 'password': 'pwd'} 

EDIT:

non ho menzionato questo prima, ma ora sento che potrebbe essere rilevante. Sto usando la libreria Python Requests e un altro post sembra suggerire che non dovresti mai codificare i parametri su un oggetto request: https://stackoverflow.com/a/14804320/1012040

"Indipendentemente dal fatto che GET/POST non devi mai ricodificare i parametri, basta semplicemente un dizionario come argomento ed è bello andare. "

Sembra che la serializzazione non sia necessaria?

La mia richiesta oggetto:

response = requests.post(url, data=data, headers=headers) 
+1

dovresti postare il resto del tuo codice. Potrei creare un http api in cui entrambi funzionerebbero in modo equivalente. – cwa

+0

non è un'API pubblica, o/w Vorrei :(Stai dicendo che questa potrebbe essere solo una funzione dell'API specifica rispetto a qualcosa di generale alle richieste HTTP? – acpigeon

+1

Ti suggerisco di leggere la serializzazione degli oggetti. 'Json.dump 'serializza l'oggetto in modo che possa essere inviato come flusso di dati, in sostanza. L'inserimento dell'oggetto direttamente invierà attraverso un flusso binario di dati che il server non saprà come decodificare. – PhD

risposta

21

Apparentemente l'API richiede dati codificati JSON e non codificati in forma. Quando si passa un dict come parametro data, i dati sono codificati in forma. Quando si passa una stringa (come il risultato di json.dumps), i dati non sono codificati in forma.

Considerate questa citazione dalla documentazione richieste:

genere, si desidera di inviare alcuni dati del modulo con codifica - molto simile a un modulo HTML. Per fare ciò, basta passare un dizionario all'argomento dati. Il tuo dizionario di dati verrà automaticamente codificato in forma quando viene effettuata la richiesta.

Ci sono molte volte che si desidera inviare dati che non sono codificati in forma. Se passi una stringa invece di una dict, i dati verranno pubblicati direttamente.

Ad esempio, l'API v3 GitHub accetta JSON con codifica dati POST/PATCH:

>>> import json 
>>> url = 'https://api.github.com/some/endpoint' 
>>> payload = {'some': 'data'} 

>>> r = requests.post(url, data=json.dumps(payload)) 

Refs:

+3

Questo non ha funzionato per me come è. Ho dovuto aggiungere le seguenti intestazioni: headers = {'' Content-Type ':' application/json '} – redobot

1

Anche se sembrano sintatticamente itentical c'è una differenza: JSON è una rappresentazione di stringa di oggetto serializzato; in questo caso, Python ha dettato In questo esempio è necessario inviare dati serializzati in una forma di stringa e quindi json.dumps è necessario per eseguire la serializzazione.

modificare

Come suggerito nei commenti alla domanda è relativo alla API utilizzata, ma comunque la serializzazione deve essere fatto da qualche parte lungo la strada per inviare un oggetto oltre il filo.

Problemi correlati