Print the actual request/response headers and even the TLS handshake so you can see exactly what is happening and why.
Print the actual request/response headers and even the TLS handshake so you can see exactly what is happening and why.
# -v prints request/response headers and TLS handshake:
curl -v https://api.example.com/data
# --trace-ascii dumps full request + response bodies to a file:
curl --trace-ascii trace.txt https://api.example.com/data// Node: log the outgoing request and the response you get back
const opts = { method: 'GET', headers: { Accept: 'application/json' } };
console.log('->', opts);
const res = await fetch('https://api.example.com/data', opts);
console.log('<-', res.status, Object.fromEntries(res.headers));
console.log(await res.clone().text());import logging, http.client, requests
http.client.HTTPConnection.debuglevel = 1 # dump wire-level traffic
logging.basicConfig(level=logging.DEBUG)
res = requests.get('https://api.example.com/data')
print(res.request.headers) # what was actually sentcurl `-v` shows the request line and request headers (`>`), the response headers (`<`), and TLS certificate/protocol negotiation. To capture everything including bodies to a file, use `--trace-ascii <file>` (or `--trace` for binary).
In `requests`, enabling `http.client` `debuglevel` logs socket-level traffic, and `res.request.headers` reveals what the library actually attached (default `User-Agent`, automatic encodings, etc.). In the browser, the DevTools Network tab is effectively the best observability tool.
Caution: verbose output prints sensitive values like `Authorization`, `Cookie`, and tokens verbatim. Always mask them before sharing logs or attaching them to an issue. This is the first thing to turn on for 'why is it doing that?' cases like 401/403, CORS, or redirect loops.