Python全栈开发之17、tornado和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框架。

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模板引擎的编译原理,具体的实现原理等后面有时间再来补充,

 

  

时间: 2024-10-22 13:32:19

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

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

一.线程 多任务可以由多进程完成,也可以由一个进程内的多线程完成,一个进程内的所有线程,共享同一块内存python中创建线程比较简单,导入threading模块,下面来看一下代码中如何创建多线程. def f1(i): time.sleep(1) print(i) if __name__ == '__main__': for i in range(5): t = threading.Thread(target=f1, args=(i,)) t.start() print('start') # 主

python全栈开发之Python基础(1)

一. 基础知识 python的运行方式有两种: 第一种通过交互式的运行方式,通过 "开始"->"所有程序" -> "python3.x" ->"IDLE" 运行. 第二种是我们写好的Python文件双击运行. Python的帮助系统 help() 我们在交互模式下输入help(),回车后输入想要查询的函数名即可. 如果想要从帮助模式中退出到交互模式,只需要在help>后面输入help()即可. 变量 `

Python全栈开发之21、django

http://www.cnblogs.com/wupeiqi/articles/5237704.html http://www.cnblogs.com/wupeiqi/articles/5246483.html http://www.cnblogs.com/yuanchenqi/articles/5786089.html 基本配置 一 常用命令 django-admin startproject sitename python manage.py runserver 0.0.0.0 python

Python全栈开发之Django进阶

No.1 静态文件处理 项目中CSS.JS.图片都属于静态文件,一般会将静态文件存到一个单独目录中,便于管理,在HTML页面调用时,需要指定静态文件的路径,Django提供了一种解析静态文件的机制,文件可以放在项目目录下,也可以放在应用目录下 在mysite/setting.py设置文件的物理路径 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] 在static目录下创建css.js.

Python全栈开发之Django基础

[TOC] No.1 MVC&MTV MVC M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增.删.改.查操作 V全拼为View,用于封装结果,生成页面展示的html内容 C全拼为Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果 MTV M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理 V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答 T全拼为Template,与MVC中的V功能相同,负

Python全栈开发之9、面向对象、元类以及单例

前面一系列博文讲解的都是面向过程的编程,如今是时候来一波面向对象的讲解了 一.简介 面向对象编程是一种编程方式,使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用.类就是一个模板,模板里可以包含多个方法(函数),方法里实现各种各样的功能,,对象则是根据模板创建的实例,通过实例,对象可以执行类中的方法,每个对象都拥有相同的方法,但各自的数据可能不同. 二.类.对象和方法 在Python中,定义类是通过class关键字,class后面紧接着是类名,类名通常

Python全栈开发之8、装饰器详解

一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了. 一.装饰器 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),装饰器的功能非常强大,但是理解起来有些困难,因此我尽量用最简单的例子一步步的说明这个原理. 1.不带参数的装饰器 假设我定义了一个函数f,想要在不改变原来函数定义的情况下,在函数运行前打印出start,函数运行后打印出end,要实现这样一个功能该怎么实现?看下面如何用一个简单的装饰器来实现

Python全栈开发之12、html

从今天开始,本系列的文章会开始讲前端,从htnl,css,js等,关于python基础的知识可以看我前面的博文,至于python web框架的知识会在前端学习完后开始更新. 一.html相关概念 html是 htyper text markup language 即超文本标记语言,超文本就是指页面内可以包含图片.链接,甚至音乐.程序等非文字元素,而标记语言:即标记(标签)构成的语言. 网页相当于HTML文档,由浏览器解析,用来展示的,静态网页即静态的资源,如xxx.html,动态网页是html代

Python全栈开发之5、几种常见的排序算法以及collections模块提供的数据结构

在面试中,经常会遇到一些考排序算法的题,在这里,我就简单了列举了几种最常见的排序算法供大家学习,说不定以后哪天面试正好用上,文章后半段则介绍一下collections模块,因为这个模块相对于python提供的基本数据结构(list,tuple,dict)不被人们所熟悉,但是如果你对他们了解的话,用起来也是非常方便高效的. 排序算法 一.冒泡排序(BubbleSort) 步骤: 比较相邻的元素,如果第一个比第二个大,就交换他们两个. 循环一遍后,最大的数就“浮”到了列表最后的位置. 将剩下的数再次