Comment puis-je voir l'intégralité de la requête HTTP envoyée par mon application Python?

263

Dans mon cas, j'utilise la requestsbibliothèque pour appeler l'API de PayPal sur HTTPS. Malheureusement, je reçois une erreur de PayPal, et le support PayPal ne peut pas déterminer quelle est l'erreur ou ce qui la cause. Ils veulent que je "Veuillez fournir la demande entière, en-têtes inclus".

Comment puis je faire ça?

Chris B.
la source

Réponses:

499

Une méthode simple: activez la journalisation dans les versions récentes des demandes (1.x et supérieures).

Requests utilise la configuration du module http.clientet loggingpour contrôler la verbosité de la journalisation, comme décrit ici .

Manifestation

Code extrait de la documentation liée:

import requests
import logging

# These two lines enable debugging at httplib level (requests->urllib3->http.client)
# You will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA.
# The only thing missing will be the response.body which is not logged.
try:
    import http.client as http_client
except ImportError:
    # Python 2
    import httplib as http_client
http_client.HTTPConnection.debuglevel = 1

# You must initialize logging, otherwise you'll not see debug output.
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

requests.get('https://httpbin.org/headers')

Exemple de sortie

$ python requests-logging.py 
INFO:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): httpbin.org
send: 'GET /headers HTTP/1.1\r\nHost: httpbin.org\r\nAccept-Encoding: gzip, deflate, compress\r\nAccept: */*\r\nUser-Agent: python-requests/1.2.0 CPython/2.7.3 Linux/3.2.0-48-generic\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json
header: Date: Sat, 29 Jun 2013 11:19:34 GMT
header: Server: gunicorn/0.17.4
header: Content-Length: 226
header: Connection: keep-alive
DEBUG:requests.packages.urllib3.connectionpool:"GET /headers HTTP/1.1" 200 226
Inactiviste
la source
1
Merci, @ EmmettJ.Butler =) Bien que je ne sois pas sûr que cette information était disponible au moment de l'enquête initiale.
Inactiviste du
9
Notez que httplib n'est pas disponible sur Python 3. Pour rendre le code portable, remplacez import httplibpar import requests.packages.urllib3.connectionpool as httplibou utilisez six et from six.moves import http_client as httplib.
Jason R. Coombs
Dans requests2.18.1 et Python 3, l'enregistreur logging.getLogger("requests.packages.urllib3")n'existe pas ou n'a aucun effet.
Flimm
1
pour Python3 voir ici - docs.python-requests.org/en/latest/api/?highlight=debug from http.client import HTTPConnection
shershen
Malheureusement, les lignes "send:" "reply:" et "header:" ne sont pas réellement enregistrées, mais simplement imprimées sur stdout. Mais je veux avoir cette information dans les fichiers journaux!
lesnik
145
r = requests.get('https://api.github.com', auth=('user', 'pass'))

rest une réponse. Il a un attribut de demande qui contient les informations dont vous avez besoin.

r.request.allow_redirects  r.request.headers          r.request.register_hook
r.request.auth             r.request.hooks            r.request.response
r.request.cert             r.request.method           r.request.send
r.request.config           r.request.params           r.request.sent
r.request.cookies          r.request.path_url         r.request.session
r.request.data             r.request.prefetch         r.request.timeout
r.request.deregister_hook  r.request.proxies          r.request.url
r.request.files            r.request.redirect         r.request.verify

r.request.headers donne aux en-têtes:

{'Accept': '*/*',
 'Accept-Encoding': 'identity, deflate, compress, gzip',
 'Authorization': u'Basic dXNlcjpwYXNz',
 'User-Agent': 'python-requests/0.12.1'}

A ensuite r.request.datale corps comme une cartographie. Vous pouvez convertir ceci avec urllib.urlencodes'ils préfèrent:

import urllib
b = r.request.data
encoded_body = urllib.urlencode(b)

en fonction du type de réponse, l' .dataattribut -attribut peut être manquant et un .bodyattribut-être là à la place.

Skylar Saveland
la source
14
Laquelle de ces informations me donne "la demande entière, en-têtes inclus"?
Chris B.
1
ajouté un peu plus. De quoi avez-vous besoin en plus des en-têtes et du corps?
Skylar Saveland
8
Je ne sais pas exactement ce qu'ils recherchent. J'espérais capturer tout ce qui allait sur le fil pour eux, dans ce format exact, octet par octet.
Chris B.
18
C'est la façon préférée de le faire dans mon cas. Une seule remarque: le response.requestsemble être un PreparedRequestdans mon cas; il n'en a pas .datamais à la .bodyplace.
Antti Haapala
2
pour l'URL complète (avec les paramètres de la chaîne de requête), vous pouvez également utiliser response.url (ce qui est un peu différent en ce qu'elle n'est pasresponse.request...
Chuck van der Linden
7

Vous pouvez utiliser HTTP Toolkit pour faire exactement cela.

C'est particulièrement utile si vous devez le faire rapidement, sans changement de code: vous pouvez ouvrir un terminal à partir de HTTP Toolkit, exécuter n'importe quel code Python à partir de là comme d'habitude, et vous pourrez voir le contenu complet de chaque HTTP / HTTPS demander immédiatement.

Il existe une version gratuite qui peut faire tout ce dont vous avez besoin, et c'est 100% open source.

Je suis le créateur de HTTP Toolkit; Je l'ai construit moi-même pour résoudre exactement le même problème pour moi il y a quelque temps! Moi aussi, j'essayais de déboguer une intégration de paiement, mais leur SDK ne fonctionnait pas, je ne pouvais pas dire pourquoi et j'avais besoin de savoir ce qui se passait réellement pour le corriger correctement. C'est très frustrant, mais pouvoir voir le trafic brut aide vraiment.

Tim Perry
la source
5

Si vous utilisez Python 2.x, essayez d'installer un ouvreur urllib2 . Cela devrait imprimer vos en-têtes, bien que vous deviez peut-être combiner cela avec d'autres ouvreurs que vous utilisez pour atteindre le HTTPS.

import urllib2
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1)))
urllib2.urlopen(url)
Kafonek
la source
2

L' verboseoption de configuration peut vous permettre de voir ce que vous voulez. Il y a un exemple dans la documentation .

REMARQUE: Lisez les commentaires ci-dessous: Les options de configuration détaillée ne semblent plus être disponibles.

Bruno
la source
3
Il y a? Je ne le trouve pas vraiment.
BastiBen
3
@mauvais chat. Il y avait une section "Journalisation détaillée" à l'époque . Il semble qu'il ait été supprimé en décembre .
Bruno
2
Ah, ça expliquerait ça. :) Pourtant, maintenant cette question est à nouveau valide, car je n'ai pas trouvé de moyen d'imprimer tout le trafic entre le serveur et le client pour le débogage.
BastiBen
1
Existe-t-il une "nouvelle méthode" recommandée pour obtenir le même effet que la journalisation détaillée?
cbare
1
Ma réponse montre la bonne méthode pour les requêtes 1.x et supérieures.
Inactiviste