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 54.174.89.232... * Connected to md.ekstrandom.net (54.174.89.232) 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 versionHTTP/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:
- 1xx
- Informational; not used very often.
- 2xx
- OK (or various versions of it)
- 3xx
- The request was OK, but the data requested is elsewhere.
- 4xx
- There was an error in the request.
- 5xx
- 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
:
@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])
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.
Redirects
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:
- 301
- Moved Permanently — the requested resource is located somewhere else, permanently.
- 302
- Found — the requested resource is elsewhere, but future requests should still use this URL.
- 303
- 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:
@app.route('/a/<int:aid>') def animal_alias(aid): return flask.redirect(url_for('show_animal', aid=aid), code=301)
Forms
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:
form
- This element contains the form.
action
- The URL that will handle the form's data.
label
- A user-visible label for a form widget.
input
- An input field; in this case a
text
field for the animal name. button
- 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
/search?name=wombat
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'
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:
- Change the
form
to havemethod="POST"
- Change the
app.route
to saymethods=['POST']
for only handling POST, ormethods=['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.
Note
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?)