toranto 和web 基础知识

一、web基础知识

  学习web框架之前,先来看一下web基础知识,首先要明白其本质就是socket,用户对应一个socket客户端,但是如果从socket开始开发web应用程序那么效率太了,正确的做法是底层socket处理代码由专门的服务器软件实现,而对于真实开发中的python web程序来说也是一般会分为两部分:服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时,先经过web服务器,对请求的各种数据进行整理封装。之后web服务器将封装好的数据传递给应用程序,应用程序并不涉及底层的socket,由应用程序负责具体的逻辑处理,但是上面就有一个问题,那就是如何来定义一个统一的web服务器和web应用程序之间接口格式,这个接口就是WSGI,WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式。WSGI applications 可以是栈式的,这个栈的中间部分可以叫做中间件,两端是必须要实现的application和server。python标准库提供的独立WSGI服务器称为wsgiref。下面我们来看一下如何简单的自定义一个web框架。

二、自定义web框架

  HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。下面来看一下用最简单的wsgiref来实现一个web框架。

 1 from wsgiref.simple_server import make_server
 2  
 3 def application(environ, start_response):
 4     start_response('200 OK', [('Content-Type', 'text/html')])
 5     body = '<h1>hello {}</h1>'.format(environ['PATH_INFO'][1:] or 'web')
 6     return [body.encode('utf-8')]
 7     # return [b'<h1>Hello, web!</h1>']   # 这里需要注意格式
 8  
 9 httpd = make_server('', 8000, application)
10 httpd.serve_forever()

上面的东西写得太简单了,一个简单的框架还应该包括路由系统和模板引擎等基本的东西,下面我们来看一下如何自己来简单的实现一下加强版的web框架

 1 from wsgiref.simple_server import make_server
 2 import time
 3 def new():
 4     f = open('s1.html', 'r')
 5     data = f.read()
 6     f.close()
 7  
 8     # 模拟模板引擎处理数据,将html里文件的item替换成其他数据
 9     # 这里仅仅是用字符串的替换来最简单的说明下原理
10     new_data = data.replace("{{item}}", str(time.time()))
11     return new_data
12      
13 def index():
14     f = open('index.html', 'r')      //打开文件读取内容,将内容当作字符串返回给用户
15     data = f.read()
16     f.close()
17     return data
18  
19 def home():
20     return 'home'
21  
22 URLS = {                            # 定义一个字典,简单模拟路由系统
23     "/new": new,                    # 一个url对应一个函数处理
24     "/index": index,
25     "/home": home,
26 }
27  
28  
29 def application(environ, start_response):
30     start_response('200 OK', [('Content-Type', 'text/html')])
31     url = environ['PATH_INFO']
32     if url in URLS.keys():              # 不同的url执行不同的函数
33         func_name = URLS[url]
34         ret = func_name()
35     else:
36         ret = "404"
37     return [ret.encode('utf-8')]                        # 最后将结果返回
38  
39  
40 httpd = make_server('', 8000, application)
41 httpd.serve_forever()
View Code

虽然上面的代码可以用简单的字符串进行替换,来动态的返回内容,但是效率极其的低下,最好的做法是使用jinja2模板引擎。至于如何使用,这里先不讲,先讲下tronadao,然后我们看一个真正的web框架是如何使用路由系统,和模板引擎。

三、tronado

  虽然我们自己写框架,但是功能效率不行,这里看一下比较常见的web框架tronado,Tornado为python的一个非阻塞异步web frame,不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。

下面来看一下最简单的hello,world,

 1 import tornado.ioloop
 2 import tornado.web
 3  
 4 class MainHandler(tornado.web.RequestHandler):
 5     def get(self):
 6         self.write("Hello, world")
 7  
 8 application = tornado.web.Application([
 9     (r"/index", MainHandler),
10 ])
11  
12 if __name__ == "__main__":
13     application.listen(8888)
14     tornado.ioloop.IOLoop.instance().start()
View Code

上述代码执行的具体过程如下:  

  第一步:执行脚本,监听 8888 端口

  第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index

  第三步:服务器接受请求,并交由对应的类处理该请求

  第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法

  第五步:方法返回值的字符串内容发送浏览器

一、路由系统  

  web框架其中一个关键的地方就是路由系统,路由系统说简单的就是,一个url对应一个类(其他框架里面可能对应的是函数),然后相应的类里面定义get,post等方法来处理不同的请求。而且tronado支持2级路由。下面来看一下代码实现

 1 import tornado.ioloop
 2 import tornado.web
 3  
 4 class MainHandler(tornado.web.RequestHandler):
 5     def get(self):
 6         self.write("Hello, world")
 7  
 8 class StoryHandler(tornado.web.RequestHandler):
 9     def get(self, story_id):
10         self.write("You requested the story " + story_id)
11  
12 class BuyHandler(tornado.web.RequestHandler):
13     def get(self):
14         self.write("it.wxtrkbc.com/index")
15  
16 application = tornado.web.Application([
17     (r"/index", MainHandler),
18     (r"/story/([0-9]+)", StoryHandler),     # 后面的分页功能就是基于此实现的
19 ])
20  
21 application.add_handlers('it.wxtrkbc.com$', [  # 这里添加2级域名,实验的话需要改本地host
22     (r'/index', BuyHandler),                 # it.wxtrkbc.com:8888/index
23 ])
24  
25 if __name__ == "__main__":
26     application.listen(8888)
27     tornado.ioloop.IOLoop.instance().start()
View Code

二、模板引擎  

  模板引擎说简单点就是将原本的html的某些内容用一些特殊的字符串代替,然后在处理用户的不同的请求时,将html的字符串替换掉,返回给用户新的一个字符串,这样就达到了动态的html的效果。Tornado的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}。控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承,此外还可以自定义UIMethod以UIModule。下面我们来简单的看一下用法

首先看一下html文件

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link href="static/s1.css" rel="stylesheet"/>
 7     <script src="static/s1.js"></script>
 8 </head>
 9 <body>
10     <div>
11         <h2>提交内容</h2>
12         <form  method="post" action="/index">
13             <input type="text" name="xxx">
14             <input type="submit" value="提交">
15         </form>
16         <h2>显示内容</h2>
17         <ul>
18             {% for item in inp %}        //for循环
19             <li>{{item}}</li>
20             {% end %}
21         </ul>
22  
23         <h3>{{npm}}</h3>
24         <h3>{{func(npm)}}</h3>         // 自定义UIMethod
25         <h3>{% module custom() %}</h3>  // 自定义UIModule
26     </div>
27 </body>
28 </html>
View Code

下面来看一下py文件

 1 import tornado.web
 2  
 3 import tornado_s1.uimodule as md
 4 from tornado_s1 import uimethod as mt
 5  
 6 INPUT_LIST = [11, 22
 7 class MainHandler(tornado.web.RequestHandler):
 8     def get(self):  
 9         self.render("s1.html", npm='NPM', inp=INPUT_LIST)
10  
11     def post(self):
12         username = self.get_argument('xxx', None)
13         INPUT_LIST.append(username)
14         self.render("s1.html", npm='NPM', inp=INPUT_LIST)
15       
16 settings = {
17     'template_path': 'template',
18     'static_path': 'static',
19     # 'static_url_prefix': '/ss/',
20     'ui_methods': mt,
21     'ui_modules': md,
22 }
23  
24 application = tornado.web.Application([(r"/index", MainHandler), ], **settings)
25  
26 if __name__ == "__main__":
27     application.listen(8888)
28     tornado.ioloop.IOLoop.instance().start()
View Code

最后来看一下自定义的module和method,这里只是简单的演示,所以代码比较简单

 1 uimethod.py
 2  
 3 def func(self, arg):
 4     return arg.lower()
 5  
 6  
 7 uimodule.py
 8  
 9 from tornado.web import UIModule
10 from tornado import escape
11  
12 class custom(UIModule):
13     def render(self, *args, **kwargs):
14         return '123'

三、模板继承和静态缓存  

将一些公用的html,css等写到通用的文件,然后通过继承,就可以获取母板的内容,而继承的html里面只需要写特有的东西,模板继承的功能非常实用,而静态缓存则可以减少相应的请求资源,下面来看一下具体怎么用这里我就只简单看一下html文件

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <link href="{{static_url('css/chouti.css')}}" type="text/css" rel="stylesheet">  // 通过static_url引用静态文件
 6     {% block css %} {% end %}
 7 </head>
 8 <body>
 9     <div class="header">
10         <div class="header-content">     
11             {% if user_info['is_login'] %}
12                 <div class="account">
13                     <a href="#">{{user_info['username']}}</a>
14                     <a href="/logout">退出</a>
15                 </div>
16             {% else %}
17                 <div class="account">
18                     <a href="http://127.0.0.1:8888/register">注册</a>
19                     <a href="http://127.0.0.1:8888/login">登陆</a>
20                 </div>
21             {% end %}
22         </div>
23     </div>
24     <div class="content">
25         {% block body %}
26         {% end %}      
27     </div>
28     <a class="back-to-head" href="javascript:scroll(0,0)"></a>
29     {% block js %} {% end %}
30     <script>
31  
32     </script>
33 </body>
34 </html>
View Code

下面来看一下子模板的html文件

 1 {% extends '../base/layout.html' %}
 2 {% block css %}
 3 <link href="{{static_url('css/css/common.css')}}" rel="stylesheet">
 4 <link href="{{static_url('css/css/login.css')}}" rel="stylesheet">
 5 {% end %}
 6  
 7  
 8 {% block body %}
 9  
10 {% end %}
11  
12 {% block js %}
13     <script src="{{static_url('js/jquery-1.12.4.js')}}"></script>
14     <script src="{{static_url('js/login.js')}}"></script>
15 {% end %}

对于tornado框架的具体学习我们可以参考白话torantdo

 

  

posted @ 2016-08-11 09:12  龙哥1995xyabc  阅读(207)  评论(0编辑  收藏  举报