cURL by Example: Redirect Handling
Control redirect behavior. This sample shows `-L` and `--max-redirs`.
Code
# Follow redirects automatically
curl -L https://google.com
# Limit the number of redirects (prevent infinite loops)
curl -L --max-redirs 5 https://example.com
# Show headers only (useful to see where it redirects)
curl -I https://google.com
# Output: HTTP/1.1 301 Moved Permanently ... Location: https://www.google.com/
# POST redirect behavior
# By default, curl changes POST to GET on 301/302 redirects.
# Use --post301, --post302, or --post303 to control this.Explanation
By default, cURL does not automatically follow HTTP redirects (3xx status codes). When it encounters a redirect response, it simply displays the content of that redirect response itself—typically a page saying "Moved" or similar—rather than following the Location header to the new destination. This differs from web browser behavior, where redirects are followed transparently. To make cURL behave like a browser and automatically follow the Location header to the new URL, use the -L flag (or its long form --location). This is essential for web scraping, accessing resources that have moved, or working with APIs that use redirects as part of their flow. When -L is enabled, cURL follows the redirect chain until it reaches a final non-redirect destination or hits its redirect limit.
Infinite Loops & Redirect Limits: Misconfigured servers or malicious sites can create infinite redirect loops (A redirects to B, which redirects back to A, etc.). To prevent cURL from running forever in such scenarios, it enforces a default limit of 50 redirects (some older versions used 30, but 50 is the current standard). Once this limit is reached, cURL stops following redirects and returns an error. You can customize this limit using --max-redirs <number> to suit your needs. For example, --max-redirs 5 would allow only 5 redirect hops before giving up. Setting the limit to -1 allows unlimited redirects, but this should be used with extreme caution and only when you're absolutely certain no redirect loops exist, as it could cause cURL to run indefinitely. The limit helps protect against both accidental misconfigurations and potentially malicious redirect chains.
POST Redirect Behavior & Method Preservation: HTTP redirect handling has nuanced rules regarding request method preservation. When a POST request receives a 301 (Moved Permanently), 302 (Found), or 303 (See Other) redirect, cURL's default behavior—mirroring historical browser behavior—is to change the subsequent request method to GET, discarding any request body or form data from the original POST. This aligns with how most web browsers have historically handled these redirects, even though it deviates from strict HTTP specifications for certain codes. For 301 and 302, the HTTP specification technically states the method should be preserved, but browsers changed to GET for historical reasons, and cURL follows this convention. For 303, the specification explicitly indicates the next request should be GET. However, if you need to maintain the POST method and resubmit form data to the redirected URL, cURL provides specific flags for fine-grained control: --post301 forces POST to be maintained after a 301 redirect, --post302 does the same for 302 redirects, and --post303 maintains POST even after a 303 (though this goes against the 303 specification's intent). In contrast, 307 (Temporary Redirect) and 308 (Permanent Redirect) responses cause cURL to resend the subsequent request using the same HTTP method by design—these newer status codes were specifically created to address the method-changing ambiguity of 301/302.
Debugging Redirects: The -I flag (or --head) performs a HEAD request, fetching only the response headers without the body. This is invaluable for debugging redirect chains because you can see the HTTP status code (301, 302, 303, 307, 308, etc.) and the Location header showing where the redirect points, without downloading potentially large response bodies. Combining -I with -L shows headers for all intermediate redirects and the final destination. Alternatively, using -v (verbose) or -i (include headers) with -L provides complete visibility into the entire redirect chain, which is crucial for diagnosing why a resource isn't loading correctly or understanding complex redirect patterns. For authentication-related redirects, note that by default cURL only sends credentials to the initial host; use --location-trusted if redirects lead to different hosts that also require the same credentials, though be cautious with this flag for security reasons.
Code Breakdown
-L follows the redirect chain automatically.--max-redirs prevents infinite loops by capping the number of hops.-I performs a HEAD request to inspect headers without downloading the body.--post301 to force POST after a 301 redirect.
