Lecture 6.1 (Tuesday, Feb. 23, 2016)

  • Return quiz 1
  • Quiz 2 is on Thursday (we will talk at end of class about what is on it)
  • Moving forward with HTTP

Walk through exam solutions

HTTP Response Codes

When all is well, we get a 200 OK response from the server:

$ curl -v http://md.ekstrandom.net/robots.txt
*   Trying
* Connected to md.ekstrandom.net ( port 80 (#0)
> GET /robots.txt HTTP/1.1
> Host: md.ekstrandom.net
> User-Agent: curl/7.43.0
> Accept: */*
< HTTP/1.1 200 OK
< Date: Mon, 22 Feb 2016 16:13:00 GMT
< Server: Apache/2.2.15 (Red Hat) PHP/5.4.40
< Last-Modified: Mon, 05 Oct 2015 00:26:10 GMT
< ETag: "221fed24-30-521508f5eac80"
< Accept-Ranges: bytes
< Content-Length: 48
< Content-Type: text/plain
< Vary: Accept-Encoding
User-agent: *
Disallow: /s/
Disallow: /private/

In the curl output, lines prefixed with > are the request sent to the server, and < indicates response headers.

Let's review the parts of the request and response:

Request line
This contains the method (GET), the path (/robots.txt), and the protocol version HTTP/1.1.
Request headers
These contain additional information to help produce the response.
Response line
Contains the HTTP version (HTTP/1.1), response code (200), and reason (OK).
Response headers
Contain additional data about the response, such as the length and content type.
Response body
After the empty < line, contains the actual response content.

You've probably already seen a couple of other codes:

  • 500 when there's a Python problem
  • 404 when you're visiting a URL with no route

404 is the generic ‘nothing to see here’ response. It means ‘not found’.

Classes of HTTP Codes

To review:

Informational; not used very often.
OK (or various versions of it)
The request was OK, but the data requested is elsewhere.
There was an error in the request.
The server had a problem handling the request.

Implementing 404 Codes

Let's consider the Animals example code again.

Suppose we write URL to view an animal that does not exist.

It'll 500.

But we would rather 404, since that is what really happened. To do this, we use flask.abort:

def show_animal(aid):
    if aid < 0 || aid >= len(animals):
        # 'abort' throws an exception, so code will stop here
    return flask.render_template('animal.html', animals[aid])

The abort function allows us to fail with any standard HTTP error code. For example, if you know that an item used to exist but it no longer does, you can fail with 410 to send a ‘Gone’ response.


We've seen the 200s — everything's good — and the 400s, particularly ‘Not Found’.

The 3xx class of responses say look elsewhere. The common ones are:

Moved Permanently — the requested resource is located somewhere else, permanently.
Found — the requested resource is elsewhere, but future requests should still use this URL.
See Other — used in form handling (we'll see this in a bit).

All of these return a Location header that specifies the new URL.

The difference between 301 and 302 is in its permanency: if a URL returns 301, then it is fine for the browser to always use the new URL; if it's 302, it should keep using the current URL. It is the difference between ‘content moved’ and ‘content somewhere else, that might change, but I'll keep you updated’.

Sending Redirects

To send a redirect, return the results of calling flask.redirect.

Let's create a permanent redirect for an animal:

def animal_alias(aid):
    return flask.redirect(url_for('show_animal', aid=aid), code=301)


Let's add a new HTML element: forms.

Forms let us send data to the server.

Let's make a really basic query form to look for animals:

<form action="/search">
<label>Name: <input type="text" name="name" placeholder="animal"></label>
<button type="submit">Search</button>

There are a few pieces:

This element contains the form.
The URL that will handle the form's data.
A user-visible label for a form widget.
An input field; in this case a text field for the animal name.
A button to perform some action, in this case submitting the form.

When this form is submitted with an animal name of wombat, it will take the user to the URL


The key-value pairs after the ? form the query string, and are available in flask.request.args (as a dictionary).

Let's handle this:

def search():
    name = flask.request.args['name']
    # do something with 'name'

POST requests

The kind of form we have seen is good for doing things like search.

But what if the user needs to submit data that should make a change on the server?

For various reasons, this should not be done in a standard GET request:

  • GET requests can be cached, so they might not actually happen.
  • GET requests can be repeated, so they might happen twice.

The HTTP specification indicates that GET requests must be idempotent: that is, the same request twice should return equivalent data.

There is another method, POST, that is for making changes. To use it:

  1. Change the form to have method="POST"
  2. Change the app.route to say methods=['POST'] for only handling POST, or methods=['GET', 'POST'] to handle both in the same function.
  3. The POST handler should not just return a page: instead, it should return a 303 redirect to a page that shows the results of the action.


The 303 redirect is so that the user can refresh the results page without resubmitting the POST action.

Let's make a little thing that adds to a list of items.

Quiz 2

  • Anything from previous quizzes!
  • CSS selectors
  • CSS inheritance
  • HTTP status codes (and methods?)