Hi, I'm Aaron.

HTTP Statuses: The Good Ones

Most people are familiar with what “404” means, at this point. Web browsers used to explicitly say “404 Not Found” when you’d type in a web address that was no good.

Modern design tends towards omitting the status code, but it’s been made into memes and I think has a fair amount of cultural diffusion.

HTTP Statuses are a portion of the data that’s sent back from the web server as part of the response. You request a document with your web browser, and it kicks back a response. They’re all 3-digit codes, and each code corresponds with a different kind of response. 200 means “success”, 404 means “not found”, 500 means “whoops!”

Using the correct status is important because you get some behaviors for free when you use it. Using the correct redirect or “not found” status code will cause search engines to update their indexes. Web browsers implicitly understand certain certain status responses, as well.

Proper HTTP statuses are also just the “right thing to do.” It’s part of the HTTP RFC 7231. The web works because we follow the same standards, so the robots know how to talk with one another. It’s important that we keep sticking with these!

This is not an exhaustive list.

I’m curating this list based on my experience as a backend engineer, sitting between the server and the application.

100s (Informational)

In my 15 years of web development, I’ve literally never explicitly used one of these.

200s (Success!)

If you were to use only a single response code to indicate a successful request, it would be 200. This is, I imagine, the most common HTTP status response since everytime a web page is loaded successfully, it’s almost certainly the status that’s sent back.

200 (OK)

A 200 response means “OK”, as in “here’s your page, as requested!”

When you’re writing backend code, and you’re covering the happy path, and everything is happy, this is most likely the code you send back. More than likely, though, the server software you’re using will send it back for you.

201 (Created)

A 201 response means that the resource you were trying to create was successfully created. The expectation is that new resources are created via a POST verb.

204 (No Content)

A 204 is almost like a 200 except that there’s no body (content) to go with it, just the headers. When you are updating an existing resource, it’s generally done via that PUT verb, and this would commonly be the response.

206 (Partial Content)

A 206 is also similar to a 200 except this one requires a Range header to be sent. This one is used when the client is requesting a large bit of content in piecemeal, such as a large video file, 500kB at a time.

300s (Your princess is in another castle)

These are for when the request is valid but you’re not sending back actual content. Typically these are seen as the “redirects” though the lazy 304 (“you already know it”) also falls into this group.

301 (Moved Permanently)

A 301 status is the code you send back when the document is somewhere else. This is what you use when you move a page from one site to another, or if you do a restructuring and everything is in a new place now. When you send this status back, be sure to also send a Location header back too.

(There is another similar status code, 308, that is almost identical to this except the request headers are immutable. A 301 can change the HTTP verb used, but not with a 308. I can’t think of anytime I’ve ever seen or used a 308 in real life, though)

302 (Found)

This one is kind of funny. It’s called “Found” but we more commonly just call it a “Temporary Redirect”. A 302 is almost the same as a 301, otherwise. You have to also send a Location header with it. The content you were looking for is over here for now, but hang on to the old link. It’s called “Found”, but my coworkers and I always call this one the “temporary redirect” (even though that is technically 307 – similar to 308, a 307 has immutable request headers, but is for a temporary redirect.)

304 (Not Modified)

A very important status code to know, for performance! This requires some additional headers sent in with the request (If-None-Match or If-Modified-Since). When the client requests a resource and provides one of those headers, if the resource hasn’t been modified since the date provided, it responds with this status code and nothing else! Much faster, and much more performant on the server-side.

Using These Headers

Most frameworks come equipped with short-hand methods, or automatic means, of sending back the appopriate status message. Here are some examples for languages that I’ve used. You’ll want to check your docs for how to do it in your language / framework, or find out how yours handles status messages.


One strength that PHP has here is that the Apache web server actually fields a lot of the statuses. Since PHP is a file that is run through a pre-processor before responding (but it’s an actual file), if you request a file that doesn’t exist, Apache kicks back a 404 and will respond with whatever you tell it to use for 404s. If the document is found, it sends back a 200.

For redirects, you can either use .htaccess for your redirects, or you can use direct PHP:

  header('Location: /foo/bar/baz.php', 301); // a 301 (permanent) redirect
  header('Location: /foo/bar/baz.php', 302); // a 302 (permanent) redirect

You can technically use the header() method to respond with pretty much any status code (Ref), including the 4xx and 5xx headers (covered in Part 2), but most commonly I see this used for redirects. One thing you could do that I don’t see very often is to use header() to send back a 201/204 when handling a POST or PUT, respectively. Typically it just falls through as a 200.

Ruby on Rails

Rails is a little more complicated because every request at least hits the Rails stack before it’s handled. All the routes are dynamically generated and handled, so before it can know if the response should be a 200, it has to see what’s available.

200, 201, and 204 are all sent back implicitly with resourceful actions. If you do a POST#create, the response will be a 201. If you do a PUT#update, the response will be a 204.

If you have caching enabled, and a request is cached, it will automatically respond to the request with a 304. No additional action required.

Redirection is offered with the redirect_to method.

# using the literal status code
redirect_to(alternate_resource_path, :status => 301) and return

# using the friendly-looking text version
redirect_to(alternate_resource_path, :status => :moved_permanently) and return

and for temporary redirects:

# using the literal status code
redirect_to(alternate_resource_path, :status => 302) and return

# using the friendly-looking text version
redirect_to(alternate_resource_path, :status => :found) and return