online / endpoints 59 / categories 14 / rate 60/min/ip /

GET /redirect-chain

GET /redirect-chain

Redirects N times via 302 before returning a final 200. Each hop decrements the counter in the query string. Tests redirect-following limits, history tracking, and loop detection.

n Number of hops before resolving. Range: 0–20. Default: 3.
build a request:

expect: A chain of 302 redirects terminating in a 200 OK. Following clients see the final body; non-following clients see the first 302.

bash
# curl follows redirects with -L
curl -iL https://chaos.catastrophic.io/redirect-chain?n=3

# See each hop
curl -v https://chaos.catastrophic.io/redirect-chain?n=3 2>&1 | grep -E "^[<>]"
import urllib.request
# urllib follows redirects automatically (capped at ~10).
resp = urllib.request.urlopen("https://chaos.catastrophic.io/redirect-chain?n=3")
print(resp.status, resp.url)   # final URL after redirects
// fetch follows redirects by default; pass { redirect: "manual" } to disable.
const res = await fetch("https://chaos.catastrophic.io/redirect-chain?n=3");
console.log(res.status, res.redirected, res.url);
package main

import (
    "fmt"
    "net/http"
)

func main() {
    // Default client follows up to 10 redirects.
    // CheckRedirect lets you cap or trace each hop.
    client := &http.Client{
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            if len(via) >= 3 {
                return http.ErrUseLastResponse
            }
            return nil
        },
    }
    resp, _ := client.Get("https://chaos.catastrophic.io/redirect-chain?n=3")
    defer resp.Body.Close()
    fmt.Println(resp.StatusCode, resp.Request.URL.String())
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
fn main() -> Result<(), Box> {
    let client = reqwest::blocking::Client::builder()
        .redirect(reqwest::redirect::Policy::limited(3))
        .build()?;
    let resp = client
        .get("https://chaos.catastrophic.io/redirect-chain?n=3")
        .send()?;
    println!("{} {}", resp.status(), resp.url());
    Ok(())
}
// Java 11+ HttpClient. Default policy is NEVER — opt in explicitly.
import java.net.URI;
import java.net.http.*;

public class RedirectChain {
    public static void main(String[] args) throws Exception {
        var client = HttpClient.newBuilder()
            .followRedirects(HttpClient.Redirect.ALWAYS)
            .build();
        var req = HttpRequest.newBuilder(
            URI.create("https://chaos.catastrophic.io/redirect-chain?n=3")
        ).build();
        var resp = client.send(req, HttpResponse.BodyHandlers.discarding());
        System.out.println(resp.statusCode() + " " + resp.uri());
    }
}
// .NET 6+
var handler = new HttpClientHandler {
    AllowAutoRedirect = true,
    MaxAutomaticRedirections = 10,
};
using var client = new HttpClient(handler);
var resp = await client.GetAsync("https://chaos.catastrophic.io/redirect-chain?n=3");
Console.WriteLine($"{(int)resp.StatusCode} {resp.RequestMessage?.RequestUri}");
require "net/http"
# Net::HTTP doesn't follow redirects automatically — loop manually.
uri = URI("https://chaos.catastrophic.io/redirect-chain?n=3")
limit = 10
loop do
    res = Net::HTTP.get_response(uri)
    break puts("#{res.code} #{uri}") unless res.is_a?(Net::HTTPRedirection)
    raise "Too many redirects" if (limit -= 1) <= 0
    uri = URI(res["location"])
end
# Invoke-WebRequest follows redirects automatically.
# Use -MaximumRedirection to test the limit.
Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/redirect-chain?n=3' `
    -MaximumRedirection 3   # Will throw if chain exceeds 3 hops