Creating a Basic Tornado Web Application
To develop a simple Tornado web application, inherit from tornado.web.RequestHandler and override the relevant HTTP method handlers. Initialize the application, define URL mappings, start the server, and begin the I/O loop.
from tornado import web, ioloop
class IndexHandler(web.RequestHandler):
async def get(self):
self.write("Hello, World!")
if __name__ == "__main__":
app = web.Application([
(r"/", IndexHandler)
], debug=True)
app.listen(8888)
ioloop.IOLoop.current().start()
Note: Enabling debug=True starts a background thread for auto-reloading. Terminate this thread via system resource managers if needed.
Access http://localhost:8888/ to view the output.
Avoiding Synchronous Methods in Tornado
Synchronous I/O operaitons block the event loop, delaying other requests:
import time
from tornado import web, ioloop
class BlockingHandler(web.RequestHandler):
async def get(self):
time.sleep(5) # Synchronous call blocks event loop
self.write("Delayed response")
class NonBlockingHandler(web.RequestHandler):
async def get(self):
self.write("Immediate response")
app = web.Application([
(r"/blocking", BlockingHandler),
(r"/nonblocking", NonBlockingHandler)
], debug=True)
app.listen(8888)
ioloop.IOLoop.current().start()
Consecutive requests to /blocking and /nonblocking demonstrate blocking behavior. Always use asynchronous I/O in Tornado handlers.
URL Configuration and Named Routes
Use tornado.web.URLSpec for named routes and parameter handling:
from tornado.web import URLSpec
people_config = {"db_name": "people"}
urls = [
URLSpec(r"/", IndexHandler, name="home"),
URLSpec(r"/people/(\d+)/?", PeopleDetailHandler, people_config, name="people_detail"),
]
Redirect using named routes:
self.redirect(self.reverse_url("people_detail", user_id))
Pass initial data to handlers via initialize:
class PeopleDetailHandler(web.RequestHandler):
def initialize(self, db_name):
self.db = db_name
async def get(self, user_id):
print(self.db)
self.redirect(self.reverse_url("people_name", "example"))
Complete example:
from tornado import web, ioloop
from tornado.web import URLSpec
class IndexHandler(web.RequestHandler):
async def get(self):
self.write("Home")
class PeopleDetailHandler(web.RequestHandler):
def initialize(self, db_name):
self.db = db_name
async def get(self, user_id):
print(f"Database: {self.db}")
self.redirect(self.reverse_url("people_name", "sample_name"))
class PeopleNameHandler(web.RequestHandler):
async def get(self, name):
self.write(f"Name: {name}")
class PeopleInfoHandler(web.RequestHandler):
async def get(self, name, age, gender):
self.write(f"Name: {name}, Age: {age}, Gender: {gender}")
people_config = {"db_name": "people"}
urls = [
URLSpec(r"/", IndexHandler, name="home"),
URLSpec(r"/people/(\d+)/?", PeopleDetailHandler, people_config, name="people_detail"),
URLSpec(r"/people/(\w+)/?", PeopleNameHandler, name="people_name"),
URLSpec(r"/people/(?P<name>\w+)/(?P<age>\d+)/(?P<gender>\w+)/?",
PeopleInfoHandler, name="people_info"),
]
if __name__ == "__main__":
app = web.Application(urls, debug=True)
app.listen(8888)
ioloop.IOLoop.current().start()
Configuration with Options
Use define, options, parse_command_line, and parse_config_file for runtime configuration:
conf.cfg:
port=8002
debug=True
Application code:
from tornado import web, ioloop, options
define('port', default=8008, help="Listening port", type=int)
define('debug', default=True, help="Debug mode", type=bool)
options.parse_config_file("conf.cfg")
class MainHandler(web.RequestHandler):
async def get(self):
self.write("Hello")
if __name__ == "__main__":
app = web.Application([(r"/", MainHandler)], debug=options.debug)
app.listen(options.port)
ioloop.IOLoop.current().start()
Run with: python app.py --port=8002
RequestHandler Utilities
Key methods:
initialize(): Constructor-like initializationprepare(): Pre-request setupon_finish(): Post-request cleanupwrite_error(status_code, **kwargs): Custom error handling
Example:
import traceback
class CustomHandler(web.RequestHandler):
def initialize(self, db):
self.db = db
def prepare(self):
pass # Pre-request logic
def on_finish(self):
pass # Cleanup
def write_error(self, status_code, **kwargs):
self.write("Custom error page\n")
if "exc_info" in kwargs:
self.write("Details:\n")
for line in traceback.format_exception(*kwargs["exc_info"]):
self.write(line)
self.finish()
Parameter Handling
get_argument(name): Single valueget_arguments(name): List of valuesrequest.arguments: All parameters- JSON body:
json.loads(self.request.body)
Response Control
finish(): Ends response, optionally with dataset_status(code): HTTP status code
Handler Subclasses
RedirectHandler: Permanent redirectsStaticFileHandler: Serve static files
Example:
from tornado.web import StaticFileHandler, RedirectHandler
app = web.Application([
(r"/old", RedirectHandler, {"url": "/new"}),
(r"/static/(.*)", StaticFileHandler, {"path": "/var/www/static"})
])
Template Rendering
Configure templtae path:
settings = {
"template_path": "templates",
"static_path": "/path/to/static",
"static_url_prefix": "/static/"
}
app = web.Application(handlers, **settings)
Render templates with data:
class TemplateHandler(web.RequestHandler):
async def get(self):
greeting = "Welcome"
self.render("hello.html", greeting=greeting)
templates/hello.html:
<h1>{{ greeting }}</h1>
Template features:
- Variables:
{{ var }} - Control structures:
{% if %}...{% end %},{% for %}...{% end %} - Built-in functions:
escape,url_escape,json_encode,squeeze - Raw output:
{% raw variable %}