¿Cómo envío una solicitud POST como JSON?

105
data = {
        'ids': [12, 3, 4, 5, 6 , ...]
    }
    urllib2.urlopen("http://abc.com/api/posts/create",urllib.urlencode(data))

Quiero enviar una solicitud POST, pero uno de los campos debe ser una lista de números. Cómo puedo hacer eso ? (¿JSON?)

TIMEX
fuente
1
Sin embargo, ¿no es eso ya una lista de números?
Waynn Lue
Esto no se puede responder sin saber qué tipo de entrada espera la API.
Niklas B.
1
@WaynnLue, el servidor API lo obtiene como una cadena, no como una lista.
TIMEX
1
¿Tengo que configurar los encabezados como "application / json" o algo así?
TIMEX

Respuestas:

154

Si su servidor espera que la solicitud POST sea json, entonces deberá agregar un encabezado y también serializar los datos para su solicitud ...

Python 2.x

import json
import urllib2

data = {
        'ids': [12, 3, 4, 5, 6]
}

req = urllib2.Request('http://example.com/api/posts/create')
req.add_header('Content-Type', 'application/json')

response = urllib2.urlopen(req, json.dumps(data))

Python 3.x

https://stackoverflow.com/a/26876308/496445


Si no especifica el encabezado, será el application/x-www-form-urlencodedtipo predeterminado .

jdi
fuente
Tengo una pregunta. ¿Es posible agregar varios elementos en el encabezado ... como el tipo de contenido y la identificación del cliente ... @jdi
Omar Jandali
@OmarJandali, solo add_header()vuelve a llamar , por cada encabezado que quieras agregar.
jdi
Tengo el siguiente código pero no imprime nada. se suponía que debía imprimir la URL y los encabezados, pero no se imprimió nada ... req = urllib.Request('http://uat-api.synapsefi.com') req.add_header('X-SP-GATEWAY', 'client_id_asdfeavea561va9685e1gre5ara|client_secret_4651av5sa1edgvawegv1a6we1v5a6s51gv') req.add_header('X-SP-USER-IP', '127.0.0.1') req.add_header('X-SP-USER', '| ge85a41v8e16v1a618gea164g65') req.add_header('Content-Type', 'application/json') print(req)...
Omar Jandali
urllib2 no fue reconocido, así que solo usé urllib. También recibo un error con la solicitud. The view tab.views.profileSetup didn't return an HttpResponse object. It returned None instead. @jdi
Omar Jandali
@OmarJandali, tenga en cuenta que esta respuesta se dio originalmente en 2012, bajo python 2.x. Estás utilizando Python3, por lo que las importaciones serán diferentes. Ahora sería import urllib.requesty urllib.request.Request(). Además, imprimir el objeto req no hace nada interesante. Puede ver claramente que los encabezados se han agregado al imprimir req.headers. Más allá de eso, no estoy seguro de por qué no funciona en su aplicación.
jdi
113

Recomiendo usar el requestsmódulo increíble .

http://docs.python-requests.org/en/v0.10.7/user/quickstart/#custom-headers

url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}

response = requests.post(url, data=json.dumps(payload), headers=headers)
FogleBird
fuente
Esto me daTypeError: post() takes from 1 to 2 positional arguments but 3 were given
zakdances
66

para Python 3.4.2 encontré que lo siguiente funcionará:

import urllib.request
import json      

body = {'ids': [12, 14, 50]}  

myurl = "http://www.testmycode.com"
req = urllib.request.Request(myurl)
req.add_header('Content-Type', 'application/json; charset=utf-8')
jsondata = json.dumps(body)
jsondataasbytes = jsondata.encode('utf-8')   # needs to be bytes
req.add_header('Content-Length', len(jsondataasbytes))
print (jsondataasbytes)
response = urllib.request.urlopen(req, jsondataasbytes)
mike gold
fuente
1
Python3.6.2 esto funcionó. Solo agregar encabezado con req.add_header (...) funcionó para mí.
Shalin LK
18

Esto funciona perfectamente para Python 3.5, si la URL contiene un valor de cadena de consulta / parámetro,

URL de solicitud = https://bah2.com/ws/rest/v1/concept/
Valor de parámetro = 21f6bb43-98a1-419d-8f0c-8133669e40ca

import requests

url = 'https://bahbah2.com/ws/rest/v1/concept/21f6bb43-98a1-419d-8f0c-8133669e40ca'
data = {"name": "Value"}
r = requests.post(url, auth=('username', 'password'), verify=False, json=data)
print(r.status_code)
MAX
fuente
7
en su snipper de código, la variable de encabezados permanece sin usar
shookees
4

Tienes que agregar un encabezado, o obtendrás el error http 400. El código funciona bien en python2.6, centos5.4

código:

    import urllib2,json

    url = 'http://www.google.com/someservice'
    postdata = {'key':'value'}

    req = urllib2.Request(url)
    req.add_header('Content-Type','application/json')
    data = json.dumps(postdata)

    response = urllib2.urlopen(req,data)
YuanYe
fuente
2

Aquí hay un ejemplo de cómo usar el objeto urllib.request de la biblioteca estándar de Python.

import urllib.request
import json
from pprint import pprint

url = "https://app.close.com/hackwithus/3d63efa04a08a9e0/"

values = {
    "first_name": "Vlad",
    "last_name": "Bezden",
    "urls": [
        "https://twitter.com/VladBezden",
        "https://github.com/vlad-bezden",
    ],
}


headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
}

data = json.dumps(values).encode("utf-8")
pprint(data)

try:
    req = urllib.request.Request(url, data, headers)
    with urllib.request.urlopen(req) as f:
        res = f.read()
    pprint(res.decode())
except Exception as e:
    pprint(e)
Vlad Bezden
fuente
1

En el último paquete de solicitudes, puede usar el jsonparámetro in requests.post()method para enviar un dict json, y el Content-Typeencabezado in se establecerá en application/json. No es necesario especificar el encabezado de forma explícita.

import requests

payload = {'key': 'value'}

requests.post(url, json=payload)
jdhao
fuente
Tenga en cuenta que esto dará como resultado un json POSTed con comillas simples, que técnicamente no es válido.
Jethro
@Jethro ¿Ha observado errores al usar comillas simples? Es válido usar comillas simples en Python. Personalmente, no he tenido ningún problema al respecto.
jdhao
Aah, disculpas, estaba equivocado, pensé que mi servidor estaba recibiendo JSON de una sola cita, pero resultó ser un problema separado y una depuración engañosa. ¡Salud, esto es mucho más ordenado que tener que especificar el encabezado manualmente!
Jethro
0

Este me funciona bien con apis

import requests

data={'Id':id ,'name': name}
r = requests.post( url = 'https://apiurllink', data = data)
Sudhir G
fuente