在使用请求模块时,是否有办法打印原始HTTP请求?
我不仅仅需要标题,我还需要请求行、标题和内容打印输出。是否有可能看到最终从HTTP请求构造什么?
在使用请求模块时,是否有办法打印原始HTTP请求?
我不仅仅需要标题,我还需要请求行、标题和内容打印输出。是否有可能看到最终从HTTP请求构造什么?
当前回答
因为v1.2.3 Requests添加了PreparedRequest对象。根据文档,“它包含将被发送到服务器的确切字节”。
你可以用它来打印一个请求,像这样:
import requests
req = requests.Request('POST','http://stackoverflow.com',headers={'X-Custom':'Test'},data='a=1&b=2')
prepared = req.prepare()
def pretty_print_POST(req):
"""
At this point it is completely built and ready
to be fired; it is "prepared".
However pay attention at the formatting used in
this function because it is programmed to be pretty
printed and may differ from the actual request.
"""
print('{}\n{}\r\n{}\r\n\r\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
pretty_print_POST(prepared)
生产:
-----------START-----------
POST http://stackoverflow.com/
Content-Length: 7
X-Custom: Test
a=1&b=2
然后你可以用这个发送实际的请求:
s = requests.Session()
s.send(prepared)
这些链接指向可用的最新文档,因此它们的内容可能会发生变化: 高级-准备好的请求和API -低级类
其他回答
下面是一个代码,它是相同的,但有响应头:
import socket
def patch_requests():
old_readline = socket._fileobject.readline
if not hasattr(old_readline, 'patched'):
def new_readline(self, size=-1):
res = old_readline(self, size)
print res,
return res
new_readline.patched = True
socket._fileobject.readline = new_readline
patch_requests()
我花了很长时间找这个,所以我把它留在这里,如果有人需要的话。
因为v1.2.3 Requests添加了PreparedRequest对象。根据文档,“它包含将被发送到服务器的确切字节”。
你可以用它来打印一个请求,像这样:
import requests
req = requests.Request('POST','http://stackoverflow.com',headers={'X-Custom':'Test'},data='a=1&b=2')
prepared = req.prepare()
def pretty_print_POST(req):
"""
At this point it is completely built and ready
to be fired; it is "prepared".
However pay attention at the formatting used in
this function because it is programmed to be pretty
printed and may differ from the actual request.
"""
print('{}\n{}\r\n{}\r\n\r\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
pretty_print_POST(prepared)
生产:
-----------START-----------
POST http://stackoverflow.com/
Content-Length: 7
X-Custom: Test
a=1&b=2
然后你可以用这个发送实际的请求:
s = requests.Session()
s.send(prepared)
这些链接指向可用的最新文档,因此它们的内容可能会发生变化: 高级-准备好的请求和API -低级类
import requests
response = requests.post('http://httpbin.org/post', data={'key1': 'value1'})
print(response.request.url)
print(response.request.body)
print(response.request.headers)
响应对象有一个.request属性,它是被发送的PreparedRequest对象。
test_print.py内容:
import logging
import pytest
import requests
from requests_toolbelt.utils import dump
def print_raw_http(response):
data = dump.dump_all(response, request_prefix=b'', response_prefix=b'')
return '\n' * 2 + data.decode('utf-8')
@pytest.fixture
def logger():
log = logging.getLogger()
log.addHandler(logging.StreamHandler())
log.setLevel(logging.DEBUG)
return log
def test_print_response(logger):
session = requests.Session()
response = session.get('http://127.0.0.1:5000/')
assert response.status_code == 300, logger.warning(print_raw_http(response))
hello.py内容:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
Run:
$ python -m flask hello.py
$ python -m pytest test_print.py
Stdout:
------------------------------ Captured log call ------------------------------
DEBUG urllib3.connectionpool:connectionpool.py:225 Starting new HTTP connection (1): 127.0.0.1:5000
DEBUG urllib3.connectionpool:connectionpool.py:437 http://127.0.0.1:5000 "GET / HTTP/1.1" 200 13
WARNING root:test_print_raw_response.py:25
GET / HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Server: Werkzeug/1.0.1 Python/3.6.8
Date: Thu, 24 Sep 2020 21:00:54 GMT
Hello, World!
更好的想法是使用requests_toolbelt库,它可以将请求和响应都转储为字符串,以便打印到控制台。它处理了上面的解决方案不能很好处理的文件和编码的所有棘手情况。
其实很简单:
import requests
from requests_toolbelt.utils import dump
resp = requests.get('https://httpbin.org/redirect/5')
data = dump.dump_all(resp)
print(data.decode('utf-8'))
来源:https://toolbelt.readthedocs.org/en/latest/dumputils.html
你可以通过输入:
pip install requests_toolbelt