First, Introduction
Tornado is an open-source version of the extensible, non-blocking Web server and its associated tools used by FriendFeed. The web framework looks somewhat like web.py or Google's WebApp, but the web framework contains some useful tools and optimizations to make efficient use of the non-blocking server environment.
There is a significant difference between the Tornado and the current mainstream WEB server framework, including most Python frameworks: It's a non-blocking server and it's pretty fast. With its non-blocking approach and its use of epoll, Tornado can handle thousands of connections per second, which means that Tornado is an ideal web framework for real-time Web services. The main purpose of developing this WEB server is to deal with the real-time functionality of FriendFeed, where every active user maintains a server connection in the FriendFeed application. (For questions about how to scale up the server to handle the connections of thousands of clients, see c10k problem.) )
See the Tornado documentation or Tornado original document (mirroring) For more information on the WEB framework.
Download and install
Pip install PIP3 install Tornado Source Installation tar Xvzf tornado-4.4.1.tar.gzcd tornado-4.4.1python setup.py buildsudo python setup.py Inst All
SOURCE download: tornado-1.2.1.tar.gz, tornado-4.4.1.tar.gz
Tornado main modules Web-friendfeed uses the underlying WEB framework that contains most of Tornado's important features escape-xhtml, JSON, URL encoding/decoding method database-Simple for MYSQLDB encapsulation, making it easier to use template-Python-based Web Template system HttpClient-non-blocking HTTP client, which is designed to work with web and Httpserver auth-third-party authentication implementations (including Google Openid/oauth, Facebook Platform, Yahoo Bbauth, FriendFeed Openid/oauth, Twitter OAuth) locale-support options for localization and translation- command line and Profile resolution tool optimized for the server environment the underlying module Httpserver-a very simple HTTP server implementation that serves the Web module iostream-A simple encapsulation of a non-blocking socket to facilitate common read and write operations Ioloop-core The I/O loop
Second, Hello, world
"Hello, World" and application settings Basic configuration:
Import tornado.ioloopimport tornado.web# import uimodules as md# import uimethods as Mtclass MainHandler (tornado.web.Requ Esthandler): def get (self): self.write ("Hello, World") settings = { ' template_path ': ' Views ', # HTML file ' Static_path ': ' statics ', # static file (css,js,img) ' static_url_prefix ': '/statics/', # static file prefix ' Cookie_secret ': ' suoning ', # Cookie Custom string Add salt # ' xsrf_cookies ': True, # Prevent cross-site forgery # ' Ui_methods ': MT, # custom Uimethod function # ' Ui_modules ': MD, # custom uimodule Class}application = Tornado.web.Application ([ R "/ ", MainHandler),], **settings) if __name__ = =" __main__ ": application.listen (8888) Tornado.ioloop.IOLoop.instance (). Start ()
1. Processing procedures and Parameters
When the request comes, the program matches the corresponding routing address with a regular match and is delivered to the subclass of the Tornado.web.RequestHandler, and the subclass is based on the requested method (Post/get/delete ... ) and executes the appropriate method, which returns the string contents and sends it to the browser.
Self.write ("
2, overriding the method function of RequestHandlerThe process code for a request is called in the following order:
- The program creates a RequestHandler object for each request;
- Program Call
initialize()
function, the parameter of this function is the Application
definition of the keyword parameter in the configuration. (The initialize
method is newly added in Tornado 1.1, you need to rewrite in the old version __init__
to achieve the same purpose) the initialize
method generally simply saves the passed in parameter to the member variable, without producing some output or calling send_error
methods like.
- Program calls
prepare()
. Regardless of which HTTP method is used, it prepare
is called, so this method is usually defined in a base class and then reused in subclasses. prepare
output information can be generated. If it calls finish
(or Send_error '), then the entire process ends.
- The program calls an HTTP method: For example
get()
, post()
,, and put()
so on. If there is a grouping match in the regular expression pattern of the URL, then the correlation match is passed as a parameter to the method.
overriding initialize()
function (called after the RequestHandler object is created):
Class Profilehandler (Tornado.web.RequestHandler): def Initialize (self,database): self.database = Database def get (self): self.write ("Result:" + self.database) application = Tornado.web.Application ([ R "/init", Profilehandler, Dict (database= "database")])
Four, template engineThe template language in Tornao is similar to Django, where the template engine loads the template file into memory and then embeds the data in it, eventually acquiring a complete string and returning the string to the requestor.
The Tornado template supports "control statements" and "expression statements", which are used {%
and %}
wrapped for example by control statements {% if len(items) > 2 %}
. Expression statements are used {{
and }}
wrapped, for example {{items[0]}}.
The format of the control statement and the corresponding Python statement is basically exactly the same. We support if
, for
while
and try
, where these statements logically end, they need to {% end %}
be labeled. extends
template inheritance is also implemented through and block
statements. These are template
described in detail in the code documentation for the module.
Note: You need to set the template path in setting before using the template: "Template_path": "Views"
1, basic use app.py index.html other methods 2, master (template inheritance) layout.html extends.html3, import header.html index.html4, custom Uimethod to UimoduleA. Definition
uimethods.py uimodules.pyB. Registration
app.pyC. Use
Index.html v. Static files and active file cachingSpecify options in the application configuration settings static_path
to provide static file services;
Specify options in the application configuration settings static_url_prefix
to provide the static file prefix service;
{{static_url(‘XX.css‘)}}
implement proactive caching of static files when importing static files
Settings = { ' template_path ': ' Views ', ' static_path ': ' Static ', ' static_url_prefix ': '/static/',}
Vi. Cookie1, basic cookiesset_cookie
method to set the cookie in the user's browsing;
get_cookie
method to obtain a cookie in the user's browsing.
Class MainHandler (Tornado.web.RequestHandler): def get (self): if not Self.get_cookie ("MyCookie"): Self.set_cookie ("MyCookie", "myvalue") self.write ("Your cookie is not set yet!") else: self.write ("Your cookie was set!")
2. Encrypted cookie (signature)Cookies can easily be forged by malicious clients. To add information that you would like to have in your cookie to keep the current logged-in user's ID, you need to sign the cookie to prevent forgery. Tornado set_secure_cookie
get_secure_cookie
supports this function directly through and through the method. To use these methods, you need to provide a key when the app is created, named cookie_secret
. You can pass it as a keyword parameter into the app's settings:
Class MainHandler (Tornado.web.RequestHandler): def get (self): if not Self.get_secure_cookie ("MyCookie"): Self.set_secure_cookie ("MyCookie", "myvalue") self.write ("Your cookie is not set yet!") else: self.write ("Your cookie was set!") application = Tornado.web.Application ([ (R "/", MainHandler),], cookie_secret= " 61oetzkxqagaydkl5gemgejjfuyh7eqnp2xdtp1o/vo= ")
Internal algorithm source code interpretationThe nature of cryptographic Cookice:
Write Cookie process:
- To encrypt a value base64
- Hash algorithm (cannot be parsed backwards) to sign content other than value
- Stitching Signature + Encrypted value
Read the cookie process:
- Read Signature + encrypted value
- Verifying a signature
- Base64 decrypt, Get value content
Note: Many API validation mechanisms and security cookies implement the same mechanism.
User authentication based on cookie-demo user authentication based on signature cookie-demo3, JavaScript action cookieBecause cookies are stored on the browser side, JavaScript can also be used to manipulate cookies on the browser side.
/* Set the cookie to specify the number of seconds to expire */function Setcookie (name,value,expires) { var temp = []; var current_date = new Date (); Current_date.setseconds (Current_date.getseconds () + 5); Document.cookie = name + "=" + Value + "; expires=" + current_date.toutcstring ();}
For parameters:
- Cookies under domain-specific domains
- The cookie in the specified URL under path domain name
- Secure HTTPS use
Note: jquery also has the specified plugin jquery cookie specifically for manipulating cookies, bash here
Seven, user authentication
Currently authenticated user information is stored in each request processor self.current_user
, and also in the template current_user
. By default, the current_user
None
.
To implement user authentication in an application, you need to rewrite this method in the request processing get_current_user()
, where the current user's state is determined, such as through a cookie. The following example allows the user to simply use a nickname login application, which will be saved in a cookie:
class Basehandler (Tornado.web.RequestHandler): def get_current_user (self): return Self.get_secure_cookie ("U Ser ") class MainHandler (Basehandler): Def get (self): If not Self.current_user:self.redirect ("/login ") return name = Tornado.escape.xhtml_escape (self.current_user) self.write ("Hello," + Name) class L Oginhandler (Basehandler): Def get (self): Self.write (' auth to the code documentation for the module for more information. For more details. Check auth
module to learn more details. In Tornado's source code there is a Blog example, you can also see the user authentication method (and how to save the user data in the MySQL database).EightCSRFPrevention of cross-site forgery requestsCross-site forgery requests (Cross-site request forgery), referred to as XSRF, are a common security issue in personalized WEB applications. The previous link also details how the XSRF attack was implemented.
A common way to prevent XSRF is to record an unpredictable cookie data for each user, and then request that all submitted requests have this cookie data. If this data does not match, then the request may have been forged.
Tornado has built-in XSRF defense mechanism, to use this mechanism, you need to add settings in the application configuration xsrf_cookies
:
Settings = { "Cookie_secret": "61oetzkxqagaydkl5gemgejjfuyh7eqnp2xdtp1o/vo=", "Login_url": "/login", " Xsrf_cookies ": true,}application = Tornado.web.Application ([R "/", MainHandler), (R"/login ", Loginhandler) ,], **settings)
If set xsrf_cookies
, then the Tornado Web app will set a cookie value for all users _xsrf
, and if the POST
PUT
DELET
cookie value is not in the request, the request will be rejected directly. If you start this mechanism, you will need to add a field to provide this value in all the submitted forms. You can do this by using specialized functions in the template xsrf_form_html()
:
<form action= "/new_message" method= "POST" > {{xsrf_form_html ()}} <input type= "text" name= "message" /> <input type= "Submit" value= "Post"/></form>
If you are submitting an AJAX POST
request, you still need to add this value to each request through a script _xsrf
. Here is the AJAX request in FriendFeed POST
, which uses the JQuery function to add values for all request group East _xsrf
:
function GetCookie (name) { var r = document.cookie.match ("\\b" + name + "= ([^;] *) \\b "); Return r? R[1]: undefined;} Jquery.postjson = function (URL, args, callback) { args._xsrf = GetCookie ("_xsrf"); $.ajax ({url:url, data: $.param (args), DataType: "Text", type: "POST", success:function (response) { callback ( Eval ("(" + Response + ")");});};
PUT
DELETE
POST
You can also X-XSRFToken
pass XSRF tokens with this parameter in the HTTP header for and requests (and for requests that do not use the form content as parameters).
If you need to customize the XSRF behavior for each request processor, you can rewrite it RequestHandler.check_xsrf_cookie()
. For example, if you need to use an API that does not support cookies, you can check_xsrf_cookie()
disable the XSRF protection mechanism by setting empty functions. However, if you need to support both cookies and non-cookie authentication methods, it is important that you use the XSRF protection mechanism as long as the current request is authenticated by a cookie.
Nine, file upload 1, form form upload HTML Python2, Ajax upload (mainly using the first two ways) html-xmlhttprequest-xhr html-jquery html-iframe Python extension: IFRAME-based implementation Ajax Upload Example ten, verification codeTo install the image processing module:pip3 install pillow
Instance:
Verification Code Demo source download: Punch Here, note the path of the import module
Verification code Instance Python file Authenticode instance HTML file 11, non-blocking asynchronous requestWhen a request is processed, the request ends automatically. Because a non-blocking I/O model is used in the Tornado, you can change this default processing behavior--keeping a request in a connected state instead of returning immediately until a primary processing behavior returns. To implement this approach, you only need to use tornado.web.asynchronous
the adorner.
After using this adorner, you must call the self.finish()
completed htttp request, or the user's browser will remain in the state waiting for the server to respond:
Class MainHandler (Tornado.web.RequestHandler): @tornado. web.asynchronous def get (self): self.write (" Hello, World ") Self.finish ()
Here is an example of an API that uses the Tornado built-in asynchronous request HTTP client to invoke FriendFeed:
Class MainHandler (Tornado.web.RequestHandler): @tornado. web.asynchronous def get (self): http = Tornado.httpclient.AsyncHTTPClient () http.fetch ("Http://friendfeed-api.com/v2/feed/bret", callback= Self.on_response) def on_response (self, Response): if Response.error:raise tornado.web.HTTPError ($) JSON = Tornado.escape.json_decode (response.body) self.write ("fetched" + str (len (json["Entries"]) + "entries" "from the FriendFeed API") Self.finish ()
Example, when the get()
method returns, the request processing is not completed. When the HTTP client executes its callback function on_response()
, the request from the browser still exists, and the self.finish()
response is returned to the browser only after the explicit invocation.
For a high-level example of more asynchronous requests, you can refer to this example in the demo chat
. It is an AJAX chat room that uses a long polling method. If you use a long polling, you may need to make a copy on_connection_close()
so that you can do the cleanup after the client connection is closed.
12. Custom Web Component A. SessionWhat is a Session? What is the difference between a session and a cookie?
A session is a server-side mechanism (a cookie exists on the browser side) that stores the information needed for a particular user session (the session is built on demand and the cookie is the system's own); The session must rely on Cookice.
Tornado does not provide a Session mechanism by default, we can customize the following:
Demob. Form validationIn web programs, it often involves a lot of work on forms validation, such as: judging if the input is empty, and whether it conforms to the rules.
HTML PythonBecause validation rules can be reused in code, they can be defined like this:
DemoTornado WEB Framework