Python全栈开发之17、tornado和web基础知识

时间:2023-02-12 11:23:44

一、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框架。

from wsgiref.simple_server import make_server

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

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

from wsgiref.simple_server import make_server
import time
def new():
f = open('s1.html', 'r')
data = f.read()
f.close() # 模拟模板引擎处理数据,将html里文件的item替换成其他数据
# 这里仅仅是用字符串的替换来最简单的说明下原理
new_data = data.replace("{{item}}", str(time.time()))
return new_data def index():
f = open('index.html', 'r')      //打开文件读取内容,将内容当作字符串返回给用户
data = f.read()
f.close()
return data def home():
return 'home' URLS = { # 定义一个字典,简单模拟路由系统
"/new": new, # 一个url对应一个函数处理
"/index": index,
"/home": home,
} def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
if url in URLS.keys(): # 不同的url执行不同的函数
func_name = URLS[url]
ret = func_name()
else:
ret = "404"
return [ret.encode('utf-8')] # 最后将结果返回 httpd = make_server('', 8000, application)
httpd.serve_forever()

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

三、tronado

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

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

import tornado.ioloop
import tornado.web class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world") application = tornado.web.Application([
(r"/index", MainHandler),
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

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

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

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

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

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

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

一、路由系统  

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

import tornado.ioloop
import tornado.web class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world") class StoryHandler(tornado.web.RequestHandler):
def get(self, story_id):
self.write("You requested the story " + story_id) class BuyHandler(tornado.web.RequestHandler):
def get(self):
self.write("it.wxtrkbc.com/index") application = tornado.web.Application([
(r"/index", MainHandler),
(r"/story/([0-9]+)", StoryHandler),     # 后面的分页功能就是基于此实现的
]) application.add_handlers('it.wxtrkbc.com$', [  # 这里添加2级域名,实验的话需要改本地host
(r'/index', BuyHandler),     # it.wxtrkbc.com:8888/index
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

二、模板引擎  

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

首先看一下html文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="static/s1.css" rel="stylesheet"/>
<script src="static/s1.js"></script>
</head>
<body>
<div>
<h2>提交内容</h2>
<form method="post" action="/index">
<input type="text" name="xxx">
<input type="submit" value="提交">
</form>
<h2>显示内容</h2>
<ul>
{% for item in inp %} //for循环
<li>{{item}}</li>
{% end %}
</ul> <h3>{{npm}}</h3>
<h3>{{func(npm)}}</h3>      // 自定义UIMethod
<h3>{% module custom() %}</h3>  // 自定义UIModule
</div>
</body>
</html>

下面来看一下py文件

import tornado.web

import tornado_s1.uimodule as md
from tornado_s1 import uimethod as mt INPUT_LIST = [11, 22
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("s1.html", npm='NPM', inp=INPUT_LIST) def post(self):
username = self.get_argument('xxx', None)
INPUT_LIST.append(username)
self.render("s1.html", npm='NPM', inp=INPUT_LIST) settings = {
'template_path': 'template',
'static_path': 'static',
# 'static_url_prefix': '/ss/',
'ui_methods': mt,
'ui_modules': md,
} application = tornado.web.Application([(r"/index", MainHandler), ], **settings) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

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

uimethod.py

def func(self, arg):
return arg.lower() uimodule.py from tornado.web import UIModule
from tornado import escape class custom(UIModule):
def render(self, *args, **kwargs):
return '123'

三、模板继承和静态缓存  

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="{{static_url('css/chouti.css')}}" type="text/css" rel="stylesheet"> // 通过static_url引用静态文件
{% block css %} {% end %}
</head>
<body>
<div class="header">
<div class="header-content">
{% if user_info['is_login'] %}
<div class="account">
<a href="#">{{user_info['username']}}</a>
<a href="/logout">退出</a>
</div>
{% else %}
<div class="account">
<a href="http://127.0.0.1:8888/register">注册</a>
<a href="http://127.0.0.1:8888/login">登陆</a>
</div>
{% end %}
</div>
</div>
<div class="content">
{% block body %}
{% end %}
</div>
<a class="back-to-head" href="javascript:scroll(0,0)"></a>
{% block js %} {% end %}
<script> </script>
</body>
</html>

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

{% extends '../base/layout.html' %}
{% block css %}
<link href="{{static_url('css/css/common.css')}}" rel="stylesheet">
<link href="{{static_url('css/css/login.css')}}" rel="stylesheet">
{% end %} {% block body %} {% end %} {% block js %}
<script src="{{static_url('js/jquery-1.12.4.js')}}"></script>
<script src="{{static_url('js/login.js')}}"></script>
{% end %}

下面来简单的说以下tronado模板引擎的编译原理,具体的实现原理等后面有时间再来补充,

 

  

Python全栈开发之17、tornado和web基础知识的更多相关文章

  1. 战争热诚的python全栈开发之路

    从学习python开始,一直是自己摸索,但是时间不等人啊,所以自己为了节省时间,决定报个班系统学习,下面整理的文章都是自己学习后,认为重要的需要弄懂的知识点,做出链接,一方面是为了自己找的话方便,一方 ...

  2. python全栈开发之OS模块的总结

    OS模块 1. os.name()      获取当前的系统 2.os.getcwd      #获取当前的工作目录 import os cwd=os.getcwd() # dir=os.listdi ...

  3. Python全栈开发之MySQL(二)------navicate和python操作MySQL

    一:Navicate的安装 1.什么是navicate? Navicat是一套快速.可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设.它的设计符合数据库管理员.开发人员及中小 ...

  4. Python全栈开发之14、Javascript

    一.简介 前面我们学习了html和css,但是我们写的网页不能动起来,如果我们需要网页出现各种效果,那么我们就要学习一门新的语言了,那就是JavaScript,JavaScript是世界上最流行的脚本 ...

  5. Python全栈开发之1、输入输出与流程控制

    Python简介 python是吉多·范罗苏姆发明的一种面向对象的脚本语言,可能有些人不知道面向对象和脚本具体是什么意思,但是对于一个初学者来说,现在并不需要明白.大家都知道,当下全栈工程师的概念很火 ...

  6. Python全栈开发之11、进程和线程

    一.线程 多任务可以由多进程完成,也可以由一个进程内的多线程完成,一个进程内的所有线程,共享同一块内存python中创建线程比较简单,导入threading模块,下面来看一下代码中如何创建多线程. d ...

  7. Python全栈开发之21、django

    http://www.cnblogs.com/wupeiqi/articles/5237704.html http://www.cnblogs.com/wupeiqi/articles/5246483 ...

  8. Python全栈开发之MySQL(三)视图,存储过程触发器,函数,事务,索引

    一:视图 1:什么是视图? 视图是指存储在数据库中的查询的SQL语句,具有简单.安全.逻辑数据独立性的作用及视点集中简化操作定制数据安全性的优点.视图包含一系列带有名称的列和行数据.但是,视图并不在数 ...

  9. Python全栈开发之18、cookies、session和ajax等相关知识

    一.cookies 本质为在浏览器端保存的键值对,由服务端写在浏览器端,以后每次请求的时候,浏览器都携带着cookie来访问,cookies的使用之处非常多,比如用户验证,登陆界面,右侧菜单隐藏,控制 ...

随机推荐

  1. 理解&quot&semi;熵&quot&semi;

    熵描述了事物的混乱程度 一个变量x,它的可取值为x1,x2,x3,x4.当它取值为这几个值时,概率分别为p1,p2,p3,p4.那么这个混乱程度就可以描述为f(p1,p2,p3,p4). 二元取值时熵 ...

  2. lua创建文件和文件夹

    创建文件夹: os.execute('mkdir xx') 创建文件: f = assert(io.open('a.tmp','w')) f:write('test') f:close()

  3. MongoDB中的分组

    一.MongoDB中的Count函数.Distinct函数以及分组 准备工作,插入一个班级的文档 > for(var i=0;i<10;i++){ ... db.Classes.inser ...

  4. 设计模式:空对象模式(Null Object Pattern)

    设计模式:空对象模式(Null Object Pattern) 背景 群里聊到<ASP.NET设计模式>,这本书里有一个“Null Object Pattern”,大家就闲聊了一下这个模式 ...

  5. Dom2016&sol;4&sol;20

    childNode:标准情况下:包括文本节点和元素节点 非标准下:只包括元素节点 在标准情况下:包含非法嵌套的子节点. 非标准下:ie7一下的版本不包含非法嵌套的子节点 DOm的节点类型:12种 元素 ...

  6. Javascript和BHO的相互调用简介

    v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...

  7. *阿里云宕机 3 小时的 IO HANG 究竟是个什么鬼?!

    2019年3月3日凌晨,微博炸锅,有网友反映说阿里云疑似出现宕机,华北很多互联网公司受到暴击伤害,APP.网站全部瘫痪,我自己的朋友圈和微信群里也有好友反馈,刚刚从被窝被叫起来去修Bug,结果发现服务 ...

  8. mRNA基本概念

    mRNA是由DNA的一条链转录而来的(可以是正链,也可以是反链),DNA是由非编码区和编码区组成,编码区也有其特殊的结构,主要有外显子和内含子组成. mRNA的一个重要性质就是可变剪切,也就是同一个编 ...

  9. UDP ------ UDP IPPROTO&lowbar;UDPLITE 参数

    介绍 传统的 UDP 通信对整个报文进行校验 UDP-LITE 通信则可以设置校验的长度,适用于可以接受轻微的报文内容出错,比如视频数据:传统的 UDP 由于对整个报文校验,一旦出现报文数据出错就会被 ...

  10. SQL取某个字符串最后一次出现的位置后面的字符串方法

    --sql怎么取某个字符串最后一次出现的位置后面的字符串 declare @s varchar(max); set @s = 'fj/2016815/2016081553677565.pdf'; se ...