{"id":859,"date":"2025-06-10T09:27:17","date_gmt":"2025-06-10T06:27:17","guid":{"rendered":"https:\/\/www.certbolt.com\/certification\/?p=859"},"modified":"2025-12-30T14:22:34","modified_gmt":"2025-12-30T11:22:34","slug":"introduction-to-the-tornado-python-framework","status":"publish","type":"post","link":"https:\/\/www.certbolt.com\/certification\/introduction-to-the-tornado-python-framework\/","title":{"rendered":"Introduction to the Tornado Python Framework"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">The Tornado framework is a powerful and high-performance web server and web application framework written in Python. Its design focuses on scalability and efficient handling of numerous simultaneous network connections, making it a preferred choice for developers building real-time web applications. Tornado\u2019s architecture centers around non-blocking network I\/O and asynchronous programming, enabling it to handle tens of thousands of open connections concurrently.<\/span><\/p>\n<p><b>What Is a Tornado?<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado originated as an internal project at FriendFeed, a social media aggregator platform, before being open-sourced in 2009 by Facebook after acquiring FriendFeed. Unlike traditional web frameworks that operate on synchronous request-response cycles, Tornado is built for asynchronous networking. This makes it especially suitable for applications requiring long-lived connections such as WebSockets, chat platforms, and real-time data analytics.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Beyond being just a web server, Tornado provides a complete application framework. It includes HTTP client utilities and other modules designed to simplify building scalable and maintainable web services. Tornado can be run as a standalone web server or integrated into larger Python projects, offering developers flexibility in deployment and architecture.<\/span><\/p>\n<p><b>Core Concepts of Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">At its core, Tornado utilizes non-blocking I\/O to avoid waiting for operations like database queries or network requests to complete before moving on to other tasks. This enables the server to efficiently use system resources by processing many tasks concurrently without being tied up by slower operations.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s asynchronous programming model leverages Python\u2019s <\/span><span style=\"font-weight: 400;\">async<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">await<\/span><span style=\"font-weight: 400;\"> syntax (introduced in Python 3.5+) along with its event loop mechanism, <\/span><span style=\"font-weight: 400;\">IOLoop<\/span><span style=\"font-weight: 400;\">. This event loop constantly checks for events such as incoming connections, completed I\/O operations, or timer expirations, then dispatches control to the appropriate callback functions.<\/span><\/p>\n<p><b>Advantages of Non-blocking Network I\/O<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Non-blocking I\/O allows Tornado to manage high volumes of simultaneous network connections efficiently. Traditional synchronous web servers dedicate a thread or process to each connection, which can quickly exhaust system resources under heavy load. In contrast, Tornado\u2019s event-driven model handles multiple connections within a single or limited number of threads without blocking on any single request.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This approach dramatically increases the number of clients a server can support concurrently. For applications that require maintaining open connections over long periods, such as live chat or streaming services, Tornado\u2019s model ensures responsiveness and stability even under significant traffic.<\/span><\/p>\n<p><b>History and Evolution of Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado was initially developed by the engineering team at FriendFeed to meet the demand for a scalable, asynchronous web framework capable of handling real-time updates and feeds. FriendFeed\u2019s acquisition by Facebook led to the decision to open-source the framework in 2009, enabling the wider Python community to leverage its capabilities.<\/span><\/p>\n<p><b>Growth and Adoption<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Since its release, Tornado has gained popularity for projects that require robust asynchronous handling and high scalability. Its ability to combine the roles of web server, application framework, and asynchronous networking library makes it unique among Python frameworks.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Developers increasingly choose Tornado for building WebSocket-based applications, streaming services, and APIs that require persistent connections. The framework continues to evolve with contributions from its community, adopting improvements aligned with Python\u2019s evolving asynchronous programming standards.<\/span><\/p>\n<p><b>Key Features of Tornado Framework<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado is designed to perform under demanding conditions, handling thousands of simultaneous connections with low latency. Its efficient event-driven architecture minimizes overhead and maximizes throughput. This makes it suitable for I\/O-bound applications where waiting for external resources like databases or APIs is common.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Scalability in Tornado is achieved through multiple strategies, including running multiple instances of the application on different CPU cores or machines and using load balancers to distribute traffic. This horizontal scaling allows Tornado-based services to grow seamlessly as demand increases.<\/span><\/p>\n<p><b>Built-in WebSocket Support<\/b><\/p>\n<p><span style=\"font-weight: 400;\">One of Tornado\u2019s standout features is its native support for WebSockets. WebSockets provide full-duplex communication channels over a single TCP connection, allowing the server and client to send data in real-time without the need to repeatedly open and close HTTP connections.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This is essential for applications such as online gaming, chat rooms, and live dashboards, where instant data exchange improves user experience. Tornado\u2019s WebSocket handlers simplify the development process by managing connection lifecycles and message transmission within the framework.<\/span><\/p>\n<p><b>Asynchronous I\/O Library<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado includes a comprehensive asynchronous I\/O library that facilitates writing non-blocking code. The library provides tools for performing asynchronous operations such as network requests, file handling, and timers.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This allows developers to write concise, readable code that efficiently manages concurrent operations without resorting to complex threading or multiprocessing paradigms. The asynchronous I\/O library integrates tightly with Tornado\u2019s event loop, ensuring smooth execution and scalability.<\/span><\/p>\n<p><b>Flexibility and Modularity<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado is highly flexible, usable as both a standalone web server and an embeddable component within larger Python applications. Developers can customize routing, middleware, and other components to fit specific application requirements.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The modular design of Tornado encourages reusability and extensibility, allowing integration with other frameworks or libraries. This adaptability makes Tornado suitable for a broad range of use cases, from simple APIs to complex real-time platforms.<\/span><\/p>\n<p><b>Security Features<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Security is a critical aspect of web development, and Tornado provides several features out of the box. These include protections against Cross-Site Request Forgery (XSRF), secure cookie handling, and built-in support for HTTPS.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">These capabilities help developers implement robust security policies without extensive custom coding. Tornado\u2019s emphasis on security ensures that applications built with it can protect user data and resist common web vulnerabilities.<\/span><\/p>\n<p><b>Basic Structure of a Tornado Application<\/b><\/p>\n<p><span style=\"font-weight: 400;\">In Tornado, the fundamental building block of an application is the request handler. A request handler is a Python class that inherits from <\/span><span style=\"font-weight: 400;\">tornado.web.RequestHandler<\/span><span style=\"font-weight: 400;\"> defines methods corresponding to HTTP verbs like GET, POST, PUT, and DELETE.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Each method processes incoming requests, performs necessary logic such as querying databases or processing input, and sends a response back to the client. Handlers are mapped to specific URL patterns, enabling clean and organized routing within the application.<\/span><\/p>\n<p><b>Application Object<\/b><\/p>\n<p><span style=\"font-weight: 400;\">The application object, created from <\/span><span style=\"font-weight: 400;\">tornado.web.The application<\/span><span style=\"font-weight: 400;\"> serves as the central configuration point. It defines the routing table by associating URL patterns with their respective handlers and sets application-wide settings such as template paths, static file locations, and security options.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This object is passed to the Tornado HTTP server or embedded within other servers, allowing it to listen for and respond to client requests.<\/span><\/p>\n<p><b>Event Loop and IOLoop<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s event loop is managed by the <\/span><span style=\"font-weight: 400;\">IOLoop<\/span><span style=\"font-weight: 400;\"> class. This event loop continuously monitors for events like incoming data, completed asynchronous tasks, or scheduled callbacks. It then dispatches these events to their registered handlers.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Developers typically start the IOLoop in the main entry point of their application to begin processing requests. The event-driven nature of the IOLoop is central to Tornado\u2019s asynchronous performance.<\/span><\/p>\n<p><b>Example of a Minimal Tornado Application<\/b><\/p>\n<p><span style=\"font-weight: 400;\">A simple Tornado app involves defining a handler that responds to requests and creating an application instance to route requests accordingly. The server is started by calling the event loop\u2019s <\/span><span style=\"font-weight: 400;\">start<\/span><span style=\"font-weight: 400;\"> method.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This minimal structure illustrates Tornado\u2019s lightweight and straightforward API, making it accessible to both beginners and experienced developers looking to build efficient web applications.<\/span><\/p>\n<p><b>Advanced Concepts in Tornado Framework<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s core strength lies in its ability to handle asynchronous programming efficiently. Understanding how to write asynchronous code is essential to leveraging Tornado\u2019s full potential.<\/span><\/p>\n<p><b>What is Asynchronous Programming?<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Asynchronous programming allows a program to initiate potentially time-consuming operations (such as network requests, file I\/O, or database queries) and continue executing other tasks without waiting for those operations to complete. This model contrasts with synchronous programming, where the program waits (or blocks) until an operation finishes before moving on.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In Tornado, asynchronous programming is facilitated by the event loop, which manages tasks and callbacks efficiently. By using asynchronous code, Tornado can serve multiple clients concurrently, even when some operations are slow or delayed.<\/span><\/p>\n<p><b>Python\u2019s <\/b><b>async<\/b><b> and <\/b><b>await<\/b><b> Syntax<\/b><\/p>\n<p><span style=\"font-weight: 400;\">With the introduction of <\/span><span style=\"font-weight: 400;\">async<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">await<\/span><span style=\"font-weight: 400;\"> in Python 3.5, writing asynchronous code became more straightforward and readable. Tornado fully supports these keywords, allowing developers to define coroutines using <\/span><span style=\"font-weight: 400;\">async def<\/span><span style=\"font-weight: 400;\"> and pause execution at awaitable points.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.ioloop<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.web<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import asyncio<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class AsyncHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0async def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await asyncio.sleep(1)\u00a0 # Simulates an asynchronous task<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(&#171;Hello after 1 second&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This code snippet shows how the handler suspends the request for one second asynchronously without blocking the server, allowing other requests to be handled concurrently.<\/span><\/p>\n<p><b>Tornado\u2019s <\/b><b>Gen<\/b><b> Module<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Before native async\/await syntax, Tornado provided the <\/span><span style=\"font-weight: 400;\">gen<\/span><span style=\"font-weight: 400;\"> module to support asynchronous programming with generator-based coroutines. While newer code should prefer native syntax, understanding <\/span><span style=\"font-weight: 400;\">gen<\/span><span style=\"font-weight: 400;\"> can be useful when maintaining legacy Tornado projects.<\/span><\/p>\n<p><b>Request Handling and Routing<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Request handling in Tornado is versatile and powerful. The framework supports complex routing schemes, including pattern matching and parameter extraction.<\/span><\/p>\n<p><b>URL Routing Patterns<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado routes incoming requests to appropriate handlers based on URL patterns. These patterns are regular expressions that define which URLs a handler should process.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0(r&#187;\/&#187;, MainHandler),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0(r&#187;\/user\/(\\d+)&#187;, UserHandler),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In this example, the URL <\/span><span style=\"font-weight: 400;\">\/user\/123<\/span><span style=\"font-weight: 400;\"> would be routed to <\/span><span style=\"font-weight: 400;\">UserHandler<\/span><span style=\"font-weight: 400;\">, which can extract the user ID from the URL.<\/span><\/p>\n<p><b>Path Parameters and Query Strings<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado provides mechanisms to access path parameters extracted from the URL and query string parameters from the request URL.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Within a handler, path parameters are passed as method arguments, while query parameters can be accessed using <\/span><span style=\"font-weight: 400;\">get_argument<\/span><span style=\"font-weight: 400;\">:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class UserHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self, user_id):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0show_details = self.get_argument(&#171;details&#187;, default=&#187;false&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(f&#187;User ID: {user_id}, Show details: {show_details}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This example reads the <\/span><span style=\"font-weight: 400;\">user ID<\/span><span style=\"font-weight: 400;\"> from the path and <\/span><span style=\"font-weight: 400;\">details<\/span><span style=\"font-weight: 400;\"> from the query string.<\/span><\/p>\n<p><b>Handling Different HTTP Methods<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado allows handlers to define methods corresponding to HTTP verbs such as GET, POST, PUT, DELETE, PATCH, and OPTIONS. This flexibility supports RESTful API design.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For example, a handler can have:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class ItemHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self, item_id):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0# Retrieve item logic<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pass<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def post(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0# Create new item logic<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0pass<\/span><\/p>\n<p><b>Working with Templates<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado includes a powerful templating engine that allows developers to generate dynamic HTML pages easily.<\/span><\/p>\n<p><b>Template Syntax<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado templates support expressions, control structures like loops and conditionals, and template inheritance. Template files typically have the <\/span><span style=\"font-weight: 400;\">.html<\/span><span style=\"font-weight: 400;\"> extension and reside in a designated template directory.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Basic example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;html&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0&lt;body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;h1&gt;Hello, {{ name }}&lt;\/h1&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0&lt;\/body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;\/html&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This template can be rendered in a handler like this:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class HelloHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.render(&#171;hello.html&#187;, name=&#187;World&#187;)<\/span><\/p>\n<p><b>Template Inheritance<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Templates can inherit from base templates, allowing the reuse of common page elements such as headers and footers.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example base template (<\/span><span style=\"font-weight: 400;\">base.html<\/span><span style=\"font-weight: 400;\">):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;html&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0&lt;body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;header&gt;Site Header&lt;\/header&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0{% block content %}{% end %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;footer&gt;Site Footer&lt;\/footer&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0&lt;\/body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;\/html&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Child template (<\/span><span style=\"font-weight: 400;\">index.html<\/span><span style=\"font-weight: 400;\">):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">{% extends &#171;base.html&#187; %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">{% block content %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0&lt;h1&gt;Welcome to the site!&lt;\/h1&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">{% end %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This system promotes maintainability and separation of concerns in web page design.<\/span><\/p>\n<p><b>Handling Static Files<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Static assets such as images, CSS files, and JavaScript files are essential components of web applications. Tornado supports serving static files efficiently.<\/span><\/p>\n<p><b>Configuring Static Paths<\/b><\/p>\n<p><span style=\"font-weight: 400;\">You specify the directory that contains static files in the application settings:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0# handlers&#8230;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">], static_path=&#187;static&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tornado serves files under this directory when accessed via the <\/span><span style=\"font-weight: 400;\">\/static\/<\/span><span style=\"font-weight: 400;\"> URL prefix by default.<\/span><\/p>\n<p><b>Accessing Static Files in Templates<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Within templates, static files can be referenced easily using the <\/span><span style=\"font-weight: 400;\">static_url<\/span><span style=\"font-weight: 400;\"> method, which generates URLs that include cache-busting hashes when enabled.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;link rel=&#187;stylesheet&#187; href=&#187;{{ static_url(&#8216;css\/style.css&#8217;) }}&#187;&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This ensures clients always receive the latest version of static assets after updates.<\/span><\/p>\n<p><b>Managing Cookies and Sessions<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Handling user sessions is a common requirement for web applications. Tornado provides utilities for secure cookie management but does not include built-in session handling, so sessions are typically implemented on top of cookies.<\/span><\/p>\n<p><b>Secure Cookies<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s <\/span><span style=\"font-weight: 400;\">set_secure_cookie<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">get_secure_cookie<\/span><span style=\"font-weight: 400;\"> methods help store data securely in client cookies by signing them cryptographically.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class LoginHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def post(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0user_id = self.get_argument(&#171;user_id&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_secure_cookie(&#171;user&#187;, user_id)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(&#171;Logged in&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0user = self.get_secure_cookie(&#171;user&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0If user:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Self.write(f&#187;Hello, {user.decode()}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Else:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Self.write(&#171;Not logged in&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This approach protects cookie data from tampering.<\/span><\/p>\n<p><b>Implementing Sessions<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Since Tornado lacks built-in sessions, developers often use third-party libraries or implement sessions using secure cookies or server-side storage like Redis or databases.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A simple session implementation could involve storing session IDs in cookies and session data in a database.<\/span><\/p>\n<p><b>Working with Databases<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Most web applications require database integration. Tornado itself does not provide ORM (Object-Relational Mapping) tools, but works seamlessly with popular Python database libraries.<\/span><\/p>\n<p><b>Synchronous vs Asynchronous Database Access<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado applications benefit most from asynchronous database drivers to avoid blocking the event loop. Blocking calls can degrade performance by preventing Tornado from handling other connections concurrently.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Many modern databases provide asynchronous drivers or support libraries that integrate with Tornado\u2019s event loop.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Examples include:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">aiomysql<\/span><span style=\"font-weight: 400;\"> for MySQL<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">asyncpg<\/span><span style=\"font-weight: 400;\"> for PostgreSQL<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Motor<\/span><span style=\"font-weight: 400;\"> for MongoDB (asynchronous driver)<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Using these libraries, database queries can be awaited asynchronously.<\/span><\/p>\n<p><b>Example Using Asyncpg with Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import asyncpg<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.ioloop<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.web<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class DatabaseHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0async def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0conn = await asyncpg.connect(user=&#8217;user&#8217;, password=&#8217;password&#8217;, database=&#8217;db&#8217;, host=&#8217;127.0.0.1&#8242;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0result = await conn.fetch(&#8216;SELECT * FROM users&#8217;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await conn.close()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;users&#187;: [dict(record) for record in result]})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This example demonstrates fetching data asynchronously without blocking the server.<\/span><\/p>\n<p><b>WebSockets in Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">WebSockets enable full-duplex communication channels between the client and server over a single TCP connection, which is critical for real-time web applications.<\/span><\/p>\n<p><b>Implementing WebSocket Handlers<\/b><\/p>\n<p><span style=\"font-weight: 400;\">In Tornado, WebSocket support is provided via the <\/span><span style=\"font-weight: 400;\">tornado. websocket.WebSocketHandler<\/span><span style=\"font-weight: 400;\"> class. You create handlers by subclassing them and overriding methods to handle open, message, and close events.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.websocket<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class EchoWebSocket(tornado.websocket.WebSocketHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def open(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(&#171;WebSocket opened&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def on_message(self, message):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write_message(f&#187;You said: {message}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def on_close(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(&#171;WebSocket closed&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The WebSocketHandler can be added to the routing table like any other handler.<\/span><\/p>\n<p><b>Use Cases for WebSockets<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Live chat applications<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Real-time notifications and alerts<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Multiplayer games<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Collaborative tools such as document editors<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Streaming data dashboards<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">WebSockets provide a low-latency, persistent communication channel that traditional HTTP cannot achieve.<\/span><\/p>\n<p><b>Deploying Tornado Applications<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Deploying Tornado in production involves several considerations to ensure scalability, security, and reliability.<\/span><\/p>\n<p><b>Running Multiple Processes<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Since Python has a Global Interpreter Lock (GIL), a single Tornado process runs on one CPU core. For leveraging multiple cores, run multiple Tornado instances behind a load balancer.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s <\/span><span style=\"font-weight: 400;\">tornado. Process.fork_processes<\/span><span style=\"font-weight: 400;\"> utility can start multiple processes:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">from tornado.process import fork_processes<\/span><\/p>\n<p><span style=\"font-weight: 400;\">def main():<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0fork_processes(0)\u00a0 # Fork one process per CPU core<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0app = make_app()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0app.listen(8888)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0tornado.ioloop.IOLoop.current().start()<\/span><\/p>\n<p><b>Using Reverse Proxies<\/b><\/p>\n<p><span style=\"font-weight: 400;\">It is common to place Tornado behind a reverse proxy server like Nginx. The proxy handles:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">SSL\/TLS termination<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Serving static files efficiently<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Load balancing multiple Tornado instances<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">HTTP\/2 support<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">This setup improves performance and security.<\/span><\/p>\n<p><b>Monitoring and Logging<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Proper logging helps track application behavior and diagnose issues. Tornado\u2019s logging can be configured to output detailed information.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Monitoring tools like Prometheus or New Relic can be integrated for real-time metrics.<\/span><\/p>\n<p><b>Deep Dive into Tornado Framework Components<\/b><\/p>\n<p><span style=\"font-weight: 400;\">The event loop is at the heart of Tornado\u2019s asynchronous architecture. It is responsible for managing and dispatching events and callbacks, enabling the framework to handle thousands of simultaneous connections efficiently.<\/span><\/p>\n<p><b>What is an Event Loop?<\/b><\/p>\n<p><span style=\"font-weight: 400;\">An event loop continuously waits for and dispatches events or messages in a program. In Tornado, the event loop monitors network sockets, timers, and other asynchronous events. When an event occurs (e.g., a new client connection or an I\/O operation completes), the event loop triggers the appropriate callback or coroutine to process that event.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The Tornado event loop is implemented in <\/span><span style=\"font-weight: 400;\">tornado. ioloop.IOLoop<\/span><span style=\"font-weight: 400;\"> wraps the underlying OS-level event notification system, such as epoll on Linux or kqueue on macOS and BSD systems.<\/span><\/p>\n<p><b>Event Loop Life Cycle<\/b><\/p>\n<p><span style=\"font-weight: 400;\">The IOLoop typically follows this flow:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Start the loop with <\/span><span style=\"font-weight: 400;\">IOLoop.current(). .start()<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Register file descriptors (network sockets) and timers.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Wait for events or a callback.s<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Dispatch handlers to process events<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Repeat until stopped<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">The loop runs continuously until explicitly stopped, processing events as they arrive.<\/span><\/p>\n<p><b>Non-blocking Network I\/O<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s non-blocking I\/O enables high concurrency by not waiting for slow operations to finish before continuing.<\/span><\/p>\n<p><b>Blocking vs Non-blocking I\/O<\/b><\/p>\n<p><span style=\"font-weight: 400;\">In blocking I\/O, when a process performs an operation like reading from a socket or file, it halts execution until the operation completes. This causes the thread or process to wait idly, limiting concurrency.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Non-blocking I\/O, on the other hand, allows the process to initiate an operation and continue execution without waiting. The operation&#8217;s completion triggers a callback or coroutine that handles the result asynchronously.<\/span><\/p>\n<p><b>How Tornado Implements Non-blocking I\/O<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado uses the underlying OS facilities like epoll, kqueue, or select to monitor file descriptors and manage I\/O readiness events.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">When a socket is ready to be read or written, the IOLoop schedules the appropriate handler without blocking the entire process.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This approach enables Tornado to serve thousands of clients concurrently, using minimal threads and processes.<\/span><\/p>\n<p><b>Handling Long-lived Connections<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Long-lived connections, such as WebSockets or streaming HTTP connections, pose unique challenges.<\/span><\/p>\n<p><b>Challenges of Long-lived Connections<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Traditional synchronous servers may struggle to handle many long-lived connections simultaneously because each connection ties up a thread or process.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Resources can be exhausted quickly, causing degraded performance or crashes.<\/span><\/p>\n<p><b>Tornado\u2019s Approach<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s asynchronous, event-driven model is designed to maintain numerous long-lived connections efficiently.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">It leverages non-blocking sockets and the event loop to multiplex many connections without creating a new thread for each.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For example, in WebSocket communication, Tornado keeps the connection open and responds asynchronously to messages or events, freeing up resources for other connections.<\/span><\/p>\n<p><b>Understanding Request Handlers in Depth<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Request handlers in Tornado are the fundamental units that respond to client HTTP requests.<\/span><\/p>\n<p><b>RequestHandler Class<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Every handler inherits from <\/span><span style=\"font-weight: 400;\">tornado.web.RequestHandler<\/span><span style=\"font-weight: 400;\">. This base class provides methods for accessing request data, writing responses, handling cookies, and more.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Key methods include:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Get ()<\/span><span style=\"font-weight: 400;\"> \u2013 Handles HTTP GET requests<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">post()<\/span><span style=\"font-weight: 400;\"> \u2013 Handles POST requests<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Write ()<\/span><span style=\"font-weight: 400;\"> \u2013 Sends output back to the client.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">render()<\/span><span style=\"font-weight: 400;\"> \u2013 Renders templates<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">set_status()<\/span><span style=\"font-weight: 400;\"> \u2013 Sets HTTP response codes<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Handling Request Data<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Request data can come from various sources:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">URL parameters<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Query strings<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">POST data (form data or JSON)<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">HTTP headers<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Cookies<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Tornado provides convenient methods to access all these:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">get_argument(name, default=None)<\/span><span style=\"font-weight: 400;\"> for query and form parameters<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">get_body_argument(name, default=None)<\/span><span style=\"font-weight: 400;\"> for POST data<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">request.headers<\/span><span style=\"font-weight: 400;\"> for headers<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">get_cookie(name)<\/span><span style=\"font-weight: 400;\"> for cookies<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Handling JSON Requests<\/b><\/p>\n<p><span style=\"font-weight: 400;\">To process JSON POST data, you typically read the request body and parse it:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import json<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class JsonHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def post(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0data = json.loads(self.request.body)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;received&#187;: data})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This method allows Tornado to support RESTful APIs that exchange JSON data.<\/span><\/p>\n<p><b>Writing RESTful APIs with Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado is well-suited for building RESTful services because it supports handling multiple HTTP methods and easy JSON serialization.<\/span><\/p>\n<p><b>Defining RESTful Routes<\/b><\/p>\n<p><span style=\"font-weight: 400;\">You define URL routes corresponding to resources and actions:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0(r&#187;\/api\/items&#187;, ItemsHandler),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0(r&#187;\/api\/items\/(\\d+)&#187;, ItemDetailHandler),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The handlers can implement GET, POST, PUT, and DELETE methods to manage the resource.<\/span><\/p>\n<p><b>Example: CRUD API for Items<\/b><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">items = {}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class ItemsHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;items&#187;: list(items.values())})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def post(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item = json.loads(self.request.body)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item_id = str(len(items) + 1)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item[&#171;id&#187;] = item_id<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0items[item_id] = item<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(201)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(item)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class ItemDetailHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self, item_id):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item = items.get(item_id)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0If item:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(item)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Else:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(404)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;error&#187;: &#171;Item not found&#187;})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def put(self, item_id):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if item_id in items:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item = json.loads(self.request.body)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item[&#171;id&#187;] = item_id<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0items[item_id] = item<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(item)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Else:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(404)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;error&#187;: &#171;Item not found&#187;})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def delete(self, item_id):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if item_id in items:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0del items[item_id]<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(204)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Else:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(404)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;error&#187;: &#171;Item not found&#187;})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This example provides full CRUD operations on an in-memory items collection.<\/span><\/p>\n<p><b>Implementing Middleware and Request Hooks<\/b><\/p>\n<p><span style=\"font-weight: 400;\">While Tornado does not have built-in middleware like some other frameworks, developers can implement hooks to process requests globally.<\/span><\/p>\n<p><b>Using <\/b><b>prepare<\/b><b> and <\/b><b>on_finish<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">prepare()<\/span><span style=\"font-weight: 400;\"> is called before each request handler method (e.g., before <\/span><span style=\"font-weight: 400;\">get()<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">post()<\/span><span style=\"font-weight: 400;\">). It can be overridden to perform actions such as authentication, request validation, or logging.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">on_finish()<\/span><span style=\"font-weight: 400;\"> is called after the response is sent, ideal for cleanup tasks.<\/span>&nbsp;<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class BaseHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def prepare(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0# Check authentication here<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0token = self.request.headers.get(&#171;Authorization&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if not token or token != &#171;secret-token&#187;:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.set_status(401)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.finish(&#171;Unauthorized&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def on_finish(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0# Log request details<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(f&#187;Request finished: {self.request.uri}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The other handlers inherit from <\/span><span style=\"font-weight: 400;\">BaseHandler<\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><b>Exception Handling and Error Pages<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Handling errors gracefully improves user experience and aids debugging.<\/span><\/p>\n<p><b>Custom Error Handling<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Override the <\/span><span style=\"font-weight: 400;\">write_error<\/span><span style=\"font-weight: 400;\"> method in handlers to customize error responses.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class ErrorHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def write_error(self, status_code, **kwargs):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if status_code == 404:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(&#171;Custom 404: Page not found&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Else:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Self.write(f&#187;An error occurred: {status_code}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This allows sending friendly messages or JSON error payloads depending on the content type.<\/span><\/p>\n<p><b>Global Error Handling<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado allows registering default error handlers to handle uncaught exceptions or invalid routes globally.<\/span><\/p>\n<p><b>Securing Tornado Applications<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Security is a critical aspect of web development. Tornado provides several features and patterns to build secure applications.<\/span><\/p>\n<p><b>Cross-Site Request Forgery (CSRF) Protection<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado offers XSRF (Cross-Site Request Forgery) protection to prevent unauthorized requests.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">By enabling XSRF protection, Tornado automatically requires a special token to be submitted with POST requests.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Enable it by setting <\/span><span style=\"font-weight: 400;\">xsrf_cookies=True<\/span><span style=\"font-weight: 400;\"> in the application settings:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0# handlers<\/span><\/p>\n<p><span style=\"font-weight: 400;\">], xsrf_cookies=True)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Include the token in forms:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;form method=&#187;post&#187;&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;input type=&#187;hidden&#187; name=&#187;_xsrf&#187; value=&#187;{{ xsrf_token }}&#187;&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;!&#8212; other fields &#8212;&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;\/form&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This ensures that only authorized forms can submit POST requests.<\/span><\/p>\n<p><b>Secure Cookies<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s secure cookies are signed with a secret key to prevent tampering.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Set a cookie secret in application settings:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0# handlers<\/span><\/p>\n<p><span style=\"font-weight: 400;\">], cookie_secret=&#187;YOUR_SECRET_KEY&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Use <\/span><span style=\"font-weight: 400;\">set_secure_cookie<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">get_secure_cookie<\/span><span style=\"font-weight: 400;\"> to manage signed cookies.<\/span><\/p>\n<p><b>HTTPS and SSL\/TLS<\/b><\/p>\n<p><span style=\"font-weight: 400;\">While Tornado can serve HTTPS directly, it is recommended to use a reverse proxy such as Nginx for SSL termination, which provides better performance and security management.<\/span><\/p>\n<p><b>Testing Tornado Applications<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Testing is essential to ensure application reliability.<\/span><\/p>\n<p><b>Unit Testing Handlers<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado provides <\/span><span style=\"font-weight: 400;\">tornado. Testing<\/span><span style=\"font-weight: 400;\"> module with classes such as <\/span><span style=\"font-weight: 400;\">AsyncHTTPTestCase<\/span><span style=\"font-weight: 400;\"> to test handlers and asynchronous behavior.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">from tornado.testing import AsyncHTTPTestCase<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.web<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class MainHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(&#171;Hello, Test&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class MyTest(AsyncHTTPTestCase):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get_app(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return tornado.web.Application([(r&#187;\/&#187;, MainHandler)])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def test_homepage(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0response = self.fetch(&#171;\/&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.assertEqual(response.code, 200)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.assertIn(b&#187;Hello, Test&#187;, response.body)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This framework supports asynchronous test cases seamlessly.<\/span><\/p>\n<p><b>Performance Optimization<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Maximizing Tornado\u2019s performance involves several best practices:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use asynchronous libraries for database and external API calls to avoid blocking the IOLoop.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Avoid CPU-bound tasks in the main Tornado process; delegate heavy computations to background workers or separate processes.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use multiple Tornado processes to utilize all CPU cores.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Configure caching headers and compress responses to reduce bandwidth.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Serve static files via a dedicated web server or CDN.<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Scaling Tornado Applications<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Scaling a Tornado application involves both vertical and horizontal strategies.<\/span><\/p>\n<p><b>Vertical Scaling<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Running multiple processes on the same machine using Tornado\u2019s <\/span><span style=\"font-weight: 400;\">fork_processes<\/span><span style=\"font-weight: 400;\"> method or a process manager like Supervisor or systemd.<\/span><\/p>\n<p><b>Horizontal Scaling<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Deploying Tornado instances across multiple servers behind a load balancer such as Nginx, HAProxy, or cloud-based load balancing solutions.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This setup allows handling increasing loads and provides fault tolerance.<\/span><\/p>\n<p><b>Common Use Cases Revisited<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado excels in scenarios where low-latency, long-lived connections, and high concurrency are required.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Some common use cases:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Real-time chat applications<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Live dashboards with frequent updates<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">WebSocket-based games<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">IoT data ingestion servers<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Proxy servers and API gateways<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Advanced Tornado Features and Best Practices<\/b><\/p>\n<p><span style=\"font-weight: 400;\">WebSockets are a core feature of Tornado, enabling real-time, full-duplex communication channels over a single TCP connection. This capability is essential for applications that require instant data exchange, such as chat apps, live notifications, or multiplayer games.<\/span><\/p>\n<p><b>How WebSockets Work<\/b><\/p>\n<p><span style=\"font-weight: 400;\">WebSockets begin with an HTTP handshake that upgrades the connection from HTTP to the WebSocket protocol. Once established, the connection remains open, allowing bi-directional communication without repeatedly opening new HTTP connections.<\/span><\/p>\n<p><b>Tornado\u2019s WebSocket Handler<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado provides the <\/span><span style=\"font-weight: 400;\">tornado websocket.WebSocketHandler<\/span><span style=\"font-weight: 400;\"> class to implement WebSocket endpoints.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example WebSocket server:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.ioloop<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.web<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.websocket<\/span><\/p>\n<p><span style=\"font-weight: 400;\">clients = set()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class EchoWebSocket(tornado.websocket.WebSocketHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def open(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0clients.add(self)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(&#171;WebSocket opened&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def on_message(self, message):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0for client in clients:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0client.write_message(message)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def on_close(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0clients.remove(self)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0print(&#171;WebSocket closed&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Application = tornado.web.Application([<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0(r&#187;\/websocket&#187;, EchoWebSocket),<\/span><\/p>\n<p><span style=\"font-weight: 400;\">])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">if __name__ == &#171;__main__&#187;:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0application.listen(8888)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0tornado.ioloop.IOLoop.current().start()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This example broadcasts incoming messages to all connected clients, forming the basis for chat rooms or live update systems.<\/span><\/p>\n<p><b>WebSocket Security Considerations<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Validate all incoming messages carefully to prevent injection attacks.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Implement authentication mechanisms on the WebSocket handshake.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Consider rate limiting to prevent denial-of-service attacks.<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Template Rendering in Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado includes a powerful templating engine for generating dynamic HTML content.<\/span><\/p>\n<p><b>Using Tornado Templates<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Templates are stored as <\/span><span style=\"font-weight: 400;\">.html<\/span><span style=\"font-weight: 400;\"> files and use a syntax similar to Django or Jinja2 but optimized for speed.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example template (template.html):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">html<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;html&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;head&gt;&lt;title&gt;{{ title }}&lt;\/title&gt;&lt;\/head&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;h1&gt;{{ header }}&lt;\/h1&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;ul&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0{% for item in items %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;li&gt;{{ item }}&lt;\/li&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0{% end %}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&lt;\/ul&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;\/body&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;\/html&gt;<\/span><\/p>\n<p><b>Rendering Templates in Handlers<\/b><\/p>\n<p><span style=\"font-weight: 400;\">You can render templates by calling the <\/span><span style=\"font-weight: 400;\">render()<\/span><span style=\"font-weight: 400;\"> method inside request handlers:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class MainHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.render(&#171;template.html&#187;, title=&#187;My Page&#187;, header=&#187;Welcome!&#187;, items=[&#171;A&#187;, &#171;B&#187;, &#171;C&#187;])<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Templates support control structures (<\/span><span style=\"font-weight: 400;\">for<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">if<\/span><span style=\"font-weight: 400;\">), filters, inheritance, and more.<\/span><\/p>\n<p><b>Asynchronous Programming in Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado\u2019s design centers on asynchronous programming to maximize concurrency.<\/span><\/p>\n<p><b>Coroutines with <\/b><b>async<\/b><b> and <\/b><b>await<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Since Python 3.5+, Tornado supports native <\/span><span style=\"font-weight: 400;\">async<\/span><span style=\"font-weight: 400;\">\/<\/span><span style=\"font-weight: 400;\">await<\/span><span style=\"font-weight: 400;\"> syntax, simplifying asynchronous code.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.ioloop<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import tornado.web<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import asyncio<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class AsyncHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0async def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0result = await self.some_async_operation()<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write(f&#187;Result: {result}&#187;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0async def some_async_operation(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0await asyncio.sleep(1)\u00a0 # Simulate IO-bound task<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return &#171;Completed&#187;<\/span><\/p>\n<p><b>Benefits of Async Programming<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Efficiently handles many I\/O-bound tasks without blocking.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Improves scalability by avoiding thread overhead<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Leads to cleaner, more maintainable code compared to callback-based models<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Integration with Databases<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Handling data persistence is a common need in web applications. Tornado does not provide built-in ORM support but integrates easily with asynchronous database libraries.<\/span><\/p>\n<p><b>Popular Choices<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Motor<\/span><span style=\"font-weight: 400;\">: Async MongoDB driver built on top of Tornado\u2019s IOLoop<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">asyncpg<\/span><span style=\"font-weight: 400;\">: Async PostgreSQL driver compatible with async\/await<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">aiomysql<\/span><span style=\"font-weight: 400;\">: Async MySQL client<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Example: Using Motor with Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import motor.motor_tornado<\/span><\/p>\n<p><span style=\"font-weight: 400;\">client = motor.motor_tornado.MotorClient(&#8216;mongodb:\/\/localhost:27017&#8217;)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">db = client.my_database<\/span><\/p>\n<p><span style=\"font-weight: 400;\">class UserHandler(tornado.web.RequestHandler):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0async def get(self):<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0users = []<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0cursor = db.users.find({})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Async for user in cursor:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0users.append(user)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.write({&#171;users&#187;: users})<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Asynchronous drivers help keep the IOLoop unblocked, preserving Tornado\u2019s performance benefits.<\/span><\/p>\n<p><b>Managing Static Files<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado can serve static files like CSS, JavaScript, or images efficiently.<\/span><\/p>\n<p><b>Setting up Static File Handling<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Specify the static file directory in the application settings:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application(<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0handlers=[(r&#187;\/&#187;, MainHandler)],<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0static_path &#171;static&#187;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Access static files in templates or HTML using the URL <\/span><span style=\"font-weight: 400;\">\/static\/filename<\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><b>Performance Tips<\/b><\/p>\n<p><span style=\"font-weight: 400;\">For production, it is recommended to serve static content via a dedicated web server or CDN for better caching and speed.<\/span><\/p>\n<p><b>Logging and Monitoring<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Proper logging and monitoring are vital for maintaining applications in production.<\/span><\/p>\n<p><b>Tornado\u2019s Logging<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Tornado uses Python\u2019s built-in <\/span><span style=\"font-weight: 400;\">logging<\/span><span style=\"font-weight: 400;\"> module, configured by default to print to the console.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">You can customize logging levels and handlers:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">import logging<\/span><\/p>\n<p><span style=\"font-weight: 400;\">logging.basicConfig(level=logging.INFO)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">logging.info(&#171;Application started&#187;)<\/span><\/p>\n<p><b>Application Metrics and Monitoring<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Integrate monitoring tools like Prometheus to track request rates, latencies, and errors.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use third-party services for alerting and dashboards.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Implement custom metrics within Tornado handlers for detailed insight.<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Deployment Strategies<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Deploying Tornado applications requires careful planning to ensure reliability and scalability.<\/span><\/p>\n<p><b>Production Server Setup<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use a process manager like Supervisor or systemd to keep Tornado running.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Run multiple Tornado processes to utilize multiple CPU cores.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use a reverse proxy (e.g., Nginx) to manage SSL termination, serve static files, and balance load.<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Dockerizing Tornado<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Docker containers provide a consistent environment for deploying Tornado apps.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example Dockerfile snippet:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Dockerfile<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">FROM python:3.9-slim<\/span><\/p>\n<p><span style=\"font-weight: 400;\">WORKDIR \/app<\/span><\/p>\n<p><span style=\"font-weight: 400;\">COPY requirements.txt.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">RUN pip install -r requirements.txt<\/span><\/p>\n<p><span style=\"font-weight: 400;\">COPY . .<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CMD [&#171;python&#187;, &#171;app.py&#187;]<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Containers can be orchestrated with Kubernetes or other tools for scaling and management.<\/span><\/p>\n<p><b>Handling WebSocket Scalability<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Scaling WebSocket applications involves additional considerations.<\/span><\/p>\n<p><b>Sticky Sessions<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Since WebSocket connections are long-lived, load balancers should support sticky sessions to route clients to the same server.<\/span><\/p>\n<p><b>Distributed Messaging<\/b><\/p>\n<p><span style=\"font-weight: 400;\">To broadcast messages across multiple servers, integrate a message broker like Redis or RabbitMQ.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example: Use Redis Pub\/Sub to propagate WebSocket messages between Tornado instances.<\/span><\/p>\n<p><b>Debugging Tornado Applications<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Debugging asynchronous code can be challenging.<\/span><\/p>\n<p><b>Enabling Debug Mode<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Run Tornado in debug mode to get better error messages and auto-reload on code changes:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">application = tornado.web.Application(handlers, debug=True)<\/span><\/p>\n<p><b>Tools and Techniques<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use Python debuggers like <\/span><span style=\"font-weight: 400;\">pdb<\/span><span style=\"font-weight: 400;\"> or <\/span><span style=\"font-weight: 400;\">ipdb<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Use logging extensively to trace asynchronous flow.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Leverage Tornado\u2019s built-in error pages during development<\/span>&nbsp;<\/li>\n<\/ul>\n<p><b>Customizing HTTP Server<\/b><\/p>\n<p><span style=\"font-weight: 400;\">While Tornado has its own HTTP server, advanced users can customize or extend it.<\/span><\/p>\n<p><b>HTTPServer Class<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Wrap the application in <\/span><span style=\"font-weight: 400;\">tornado. httpserver.HTTPServer<\/span><span style=\"font-weight: 400;\"> to configure SSL or connection limits.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Example enabling SSL:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">python<\/span><\/p>\n<p><span style=\"font-weight: 400;\">CopyEdit<\/span><\/p>\n<p><span style=\"font-weight: 400;\">ssl_options = {<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&#171;certfile&#187;: &#171;\/path\/to\/cert.pem&#187;,<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0&#171;keyfile&#187;: &#171;\/path\/to\/key.pem&#187;,<\/span><\/p>\n<p><span style=\"font-weight: 400;\">}<\/span><\/p>\n<p><span style=\"font-weight: 400;\">http_server = tornado.httpserver.HTTPServer(application, ssl_options=ssl_options)<\/span><\/p>\n<p><span style=\"font-weight: 400;\">http_server.listen(443)<\/span><\/p>\n<p><b>Common Pitfalls and How to Avoid Them<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Blocking the IOLoop:<\/b><span style=\"font-weight: 400;\"> Avoid synchronous operations (like file or network I\/O) inside handlers. Use async libraries.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Memory leaks:<\/b><span style=\"font-weight: 400;\"> Properly close WebSocket connections and clean up resources.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Improper error handling:<\/b><span style=\"font-weight: 400;\"> Always catch exceptions and provide meaningful responses.<\/span>&nbsp;<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Ignoring security best practices:<\/b><span style=\"font-weight: 400;\"> Always enable XSRF protection and use secure cookies.<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The Tornado framework is a powerful and high-performance web server and web application framework written in Python. Its design focuses on scalability and efficient handling of numerous simultaneous network connections, making it a preferred choice for developers building real-time web applications. Tornado\u2019s architecture centers around non-blocking network I\/O and asynchronous programming, enabling it to handle tens of thousands of open connections concurrently. What Is a Tornado? Tornado originated as an internal project at FriendFeed, a social media aggregator platform, before being open-sourced in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1049,1053],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/posts\/859"}],"collection":[{"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/comments?post=859"}],"version-history":[{"count":2,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/posts\/859\/revisions"}],"predecessor-version":[{"id":9678,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/posts\/859\/revisions\/9678"}],"wp:attachment":[{"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/media?parent=859"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/categories?post=859"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.certbolt.com\/certification\/wp-json\/wp\/v2\/tags?post=859"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}