Course outline · 0% complete

0/25 lessons0%

Course overview →

Redirects: when the answer is "look elsewhere"

lesson 5-4 · ~10 min · 17/25

Following the moved sign

URLs outlive their content. Pages get renamed, sites move to new domains, and every http:// request should become https://. Without a forwarding mechanism, each of those changes would break every existing link, bookmark, and search result. The mechanism is the redirect, and you met its status class in lesson 4-3: 3xx, "look elsewhere".

A redirect response carries no useful body. Its payload is one header, Location, holding the URL to try instead:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/

The client is expected to issue a new request to that URL. Browsers do this automatically and silently, so you only notice the address bar change. The two codes to know:

  • 301 Moved Permanently: the move is forever. Browsers and caches remember it, and search engines transfer the page's ranking to the new URL.
  • 302 Found: a temporary detour, such as "after login, go back to /inbox". Nothing should remember it.

Redirects are an everyday engineering tool, covering http to https upgrades, old paths kept alive after a rename, and short links. Each one costs a full round trip from lesson 3-4 though, so chains of them are a known page-speed smell.

A recorded session

Watch redirects happen in curl. Unlike a browser, curl does NOT follow them by default, which makes it perfect for seeing the machinery.

Each step below shows the command and the output it printed.

Step 1. Request the http:// version of a site. The server does not serve the page. It answers 301 and points at the https URL in the Location header. Note the near-empty body, since the real content lives at the destination.

$ curl -i http://example.com
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
Content-Length: 0

Step 2. Add -L (follow location) and curl behaves like a browser: it reads Location, issues the new request, and prints the final page.

$ curl -L http://example.com
<!doctype html>
<html>
<head><title>Example Domain</title></head>
<body><h1>Example Domain</h1></body>
</html>

Step 3. The -w report variables tell you where you actually landed and how many hops it took, which is a quick way to detect redirect chains.

$ curl -s -o /dev/null -w '%{url_effective} after %{num_redirects} redirect(s)\n' -L http://example.com
https://example.com/ after 1 redirect(s)

Following a redirect chain by hand

The lookup function plays a set of servers. Given a URL it echoes that URL's Location header, or nothing if the URL serves real content.

lookup() {
  case $1 in
    "http://shop.example/old") echo "https://shop.example/old" ;;
    "https://shop.example/old") echo "https://shop.example/products" ;;
    *) echo "" ;;
  esac
}

url="http://shop.example/old"
hops=0

next=$(lookup "$url")
while [ -n "$next" ]; do
  echo "redirect -> $next"
  url=$next
  hops=$((hops + 1))
  next=$(lookup "$url")
done
echo "landed at $url after $hops redirects"

Output

redirect -> https://shop.example/old
redirect -> https://shop.example/products
landed at https://shop.example/products after 2 redirects

Reading the loop

  • The first hop is fetched before the loop, so while [ -n "$next" ] has something to test on its first pass. -n tests that a string is non-empty.
  • The loop exits when lookup echoes an empty string, which is this model's way of saying the URL serves real content instead of a Location header.
  • Two hops, first http to https and then the old path to the new one, is a realistic chain and exactly what -L and %{num_redirects} reveal. Each hop was a full round trip from lesson 3-4.
  • A loop like this needs a hop limit in real code. Two servers pointing at each other would spin forever, which is why browsers and curl both cap the number of redirects they will follow.

The code for a permanent move

The old server should answer 301, so browsers, caches, and search engines learn the move is permanent.

301 means permanent, so clients may cache the mapping and search engines move the page's ranking to the new address. The old URL keeps working for anyone holding an old link, while everything that can update itself does.

A 302 keeps everyone coming back to the old URL first, and keeps the search ranking there too, which is only right for temporary detours such as a post-login return.

A 404 would simply break every existing link, which is the exact failure redirects were invented to prevent. The links themselves cannot be edited, so the server has to do the forwarding.

Worth knowing that 301s are sticky. Browsers cache them aggressively, so a permanent redirect published by mistake is painful to undo, and testing with a 302 first is the cautious order of operations.

The header and the flag

The header is Location, and the flag is -L.

A 3xx response's meaning lives entirely in its Location header, which is why the body came back empty. There was never any content to send, only an address.

curl -L re-issues the request at that address, and repeatedly if the target redirects again, which is what a browser does silently.

Forgetting -L in scripts is a classic bug. The script "succeeds", because 302 is not an error, while it processes an empty redirect body instead of the real data, so the failure surfaces later as missing or malformed output.

The flag is a single capital letter, and the mnemonic is that it follows the Location.