why WSGI

来源:互联网 发布:ise14.7 端口 编辑:程序博客网 时间:2024/06/06 17:03

What's WSGI?

Here's an explanation, from wsgi.org:

WSGI is the Web Server Gateway Interface. It is a specification for web servers and application servers to communicate with web applications[...]

Note the following:

  • It's a specification,
  • It specifies how a web server should tell a web application that it has a visitor, and
  • It specifies how a web application should respond to the visitor.

Why WSGI?

  • It's an official Python standard,
  • Many Python components for web application development are standardizing on it,
  • It allows you to easily mix and match multiple HTTP-related components, and
  • It's simple.

Hello World

Let's start with Hello World, WSGI-style, in Python's interactive interpreter:

>>> def hello_world(environ, start_response):...     """A WSGI application that greets the world"""...     start_response('200 OK', [('Content-Type', 'text/plain')])...     return ['Hello World!']...>>> from wsgiref.simple_server import make_server>>> make_server('localhost', 8000, hello_world).serve_forever()

Now open up http://localhost:8000/foo/bar/ in your browser, and there's your WSGI application.

In Detail

Let's break it down:

>>> def hello_world(environ, start_response):...     """A WSGI application that greets the world"""

An application callable is declared to handle HTTP requests.

...     start_response('200 OK', [('Content-Type', 'text/plain')])

When it gets a request, it's going to respond with the HTTP status code 200 OKand an HTTP response header that explains the content's type.

...     return ['Hello World!']...

After queuing the HTTP headers, it's going to return an iterable object that yields one or more strings, which will compose the message body.

>>> from wsgiref.simple_server import make_server

Now that there's an application callable, a simple application server for it to run on is imported.

>>> make_server('localhost', 8000, hello_world).serve_forever()

Finally, the WSGI/HTTP server is run on port 8000 on localhost with thehello_world callable handling all requests. It'll do this forever, or until you hitCTRL+C to stop the infinite loop.

When someone browses to any page on your server, they'll see Hello World!

WSGI in Practice

Utilizing WSGI in practice is simple. Because WSGI components all adhere to the same interface, we can easily create a stack of components to provide the application's functionality. Components can easily be added and removed from the stack.

In this example you'll do the following:

  • Handle HTTP requests with wsgiref.simple_server,
  • Cut down on boilerplate in the controllers with Yaro,
  • Map URIs to controllers with Selector, and
  • Edit your application while it's running with Memento.

These are all WSGI components.

Prerequisites

First, get Easy Install, which will allow you to easily install Python applications and libraries. It handles finding dependencies, downloading files, and installing them into your environment.

If you're developing on Linux or BSD, and not Microsoft Windows or Mac OS X, add the following to /usr/lib/python2.5/distutils/distutils.cfg to make distutils and Easy Install install things into /usr/local:

[install]prefix = /usr/local[easy_install]site_dirs = /usr/local/lib/python$py_version_short/site-packages

Download and run the Easy Install installer:

$ wget http://peak.telecommunity.com/dist/ez_setup.py$ sudo python2.5 ez_setup.py

And get Yaro, Selector, Memento, and Static, which will be used in the example:

$ sudo easy_install yaro selector memento static

The Package

Now you'll need to make a folder for developing the application in and a Python package to hold the code:

$ mkdir wsgitest$ cd wsgitest$ mkdir wsgitest

Add a doc string in wsgitest/__init__.py that explains what the application is:

"""A WSGI application demonstration"""

The Controller

To respond to requests, you'll need some controllers.

To cut out some of the boilerplate, use Yaro with a controller inwsgitest/controllers.py:

"""CRUD controllers"""from yaro import Yaro__all__ = ['index']@Yarodef index(req):    """The application index"""    return 'Welcome to the index!'

With Yaro wrapping index, it will handle calling start_response and returning an iterable. index only needs to return a string.

The URIs

To map controllers to URIs, use Selector to create the mappings, inwsgitest/uris.py:

"""URI-to-controller mappings"""from selector import Selectorfrom wsgitest.controllers import *__all__ = ['uris']uris = Selector()uris.add('/', GET=index)

Now uris is the application callable. It dispatches HTTP requests to the controllers.

The Server

Finally, make a script to run the application.

In run.py, add a function to start the HTTP server and wrap the application function with Memento so you can edit the application while it runs:

#!/usr/bin/env python2.5"""A console script for running wsgitest"""def run(host, port):    """Runs the application on a built-in web server"""    from wsgiref.simple_server import make_server    from memento import Assassin    app = Assassin(        'wsgitest.uris:uris',        ['wsgitest'],    )    make_server(host, port, app).serve_forever()if __name__ == '__main__':    run('0.0.0.0', 8000)

Now set the script executable and start it up:

$ python2.5 run.py

You should see the index at http://localhost:8000/. While it's running, try changing the string returned by controllers.index and refresh the page. Your change is reflected automatically and you didn't need to restart the application.

Memento accomplishes this by forcing Python to re-import all modules on each HTTP request. This is obviously a bad idea in a production setting but it's great for development.

In Summary

WSGI greatly simplifies writing web applications at the low level—with the application callable interface—and simplifies modularizing functionality to abstract away common requirements and boilerplate code—by allowing middleware callables. This article shows you how to start from the bottom up, without a web framework, to build a basic application. Where you go from here is a matter of what tools you choose to use in your application!