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 22.214.171.124... * Connected to md.ekstrandom.net (126.96.36.199) 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/
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
- 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 (
- 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
- 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.
But we would rather 404, since that is what really happened. To do this, we use
@app.route('/animals/<int:aid>') def show_animal(aid): if aid < 0 || aid >= len(animals): flask.abort(404) # 'abort' throws an exception, so code will stop here return flask.render_template('animal.html', animals[aid])
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’.
To send a redirect, return the results of calling
Let's create a permanent redirect for an animal:
@app.route('/a/<int:aid>') 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> </form>
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
textfield 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:
@app.route('/search') def search(): name = flask.request.args['name'] # do something with 'name'
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
GETrequests can be cached, so they might not actually happen.
GETrequests 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:
- Change the
- Change the
methods=['POST']for only handling POST, or
methods=['GET', 'POST']to handle both in the same function.
- 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.
- Anything from previous quizzes!
- CSS selectors
- CSS inheritance
- HTTP status codes (and methods?)