一、Web框架本质

Python的Web框架分为两类:

  • 通过socket自己写程序,自己处理请求;

  • 基于Wsgi(Web Server Gateway Interface:Web服务网关接口),处理请求。

​众所周知,对于所有的Web应用而言,本质上其实就是一个socket服务端,用户浏览器其实就是一个socket客户端。

1、Socket实现Web框架的本质

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
#coding:utf-8
  
importsocket
  
def handle_request(client):
    #接收请求
    buf =client.recv(1024)
    #返回信息
    client.send("HTTP/1.1 200 OK\r\n\r\n")
    client.send("Hello, Tim")
  
def main():
    #创建sock对象
    sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #监听80端口
    sock.bind(('localhost',8000))
    #最大允许排队的客户端
    sock.listen(5)
  
    #循环
    whileTrue:
        #等待用户的连接,默认accept阻塞当有请求的时候往下执行
        connection, address =sock.accept()
        #把连接交给handle_request函数
        handle_request(connection)
        #关闭连接
        connection.close()
  
if__name__ =='__main__':
    main()

上述通过socket来实现了其本质,而对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。

不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

2、WSGI

WSGI是一种规范,它定义了使用Python编写web app与web server之间接口格式,实现web app与web server 间的解耦。

Python标准库提供的独立WSGI服务器为wsgiref,下来例子为Python3版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env python
#-*- coding:utf-8 -*-
 
from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server
 
 
def simple_app(environ, start_response):
    setup_testing_defaults(environ)
 
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
 
    start_response(status, headers)
 
    ret = ["%s: %s\n" % (key, value)
           for key, value in environ.iteritems()]
    return ret
 
 
if __name__ == '__main__':
    httpd = make_server('', 8000, simple_app)
    print "Serving on port 8000..."
    httpd.serve_forever()

下面看WEB框架图:

基于Python的Web框架有以下常用几种:

  • Tornado:使用自己的异步非阻塞的WSGI;

  • Flask:只提供了最精简和基本的框架,轻量级的;

  • Django:直接使用了WSGI,并实现了大部分功能。

二、自定义Web框架​

1、通过python标准库提供的wsgiref模块开发一个自己的Web框架

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python    
#coding:utf-8
from wsgiref.simple_server import make_server
 
 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, World!</h1>'
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

上面的代码,当我们访问时,访问任何的URL都会显示"Hello,World",这显然不是我们先要的结果。下面我们可以根据用户输入的URL不同,返回不同的字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python
# coding:utf-8
from wsgiref.simple_server import make_server
 
 
def RunServer(environ, start_response):
    """
    根据url的不同,返回不同的字符串
    :param environ: 当请求过来之后执行RunServer,wsgi给咱们封装了这些请求,这些请求都封装到了environ和start_response里
    :param start_response:
    :return:
    """
    start_response('200 OK', [('Content-Type', 'text/html')])
     
    request_url = environ['PATH_INFO']
    print request_url
     
    #根据URL做不同的响应
    # print environ 这里可以通过Pycharm断点来查看environ封装的数据
     
    if request_url == '/index':
        return "Hello Home"
    elif request_url == '/admin':
        return "Hello admin"
    else:
        return '<h1>404!</h1>'
 
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

看上面的操作,如果别人使用上面定义的框架,当用户来访问的时候,如果URL少还行,如果很多的话,就不是很完美了,为了解决这个问题,我们将上面代码做相对应修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/env python
#-*- coding:utf-8 -*-
 
from wsgiref.simple_server import make_server
 
'''可以进行拆分---这一部分可以给框架使用者,按照定义的格式来操作'''
 
def index():
    return 'index'
 
def login():
    return 'login'
 
 
#1 定义一个列表,上面定义函数
url_list = [
    #这里吧URL和函数做一个对应
    ('/index/',index),
    ('/login/',login),
]
 
########################################################################
 
'''这一部分可以单独拿出来,作为框架开发者,框架使用'''
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    #根据url的不同,返回不同的字符串
    #1 获取URL[URL从哪里获取?当请求过来之后执行RunServer,wsgi给咱们封装了这些请求,这些请求都封装到了,environ & start_response]
    request_url = environ['PATH_INFO']
    #2 根据URL做不同的相应
    #print environ #这里可以通过断点来查看它都封装了什么数据
 
    #循环这个列表
    for url in url_list:
        #如果用户请求的url和咱们定义的rul匹配
        if request_url == url[0]:
            print url
            return url[1]()
            #执行里面的方法
    else:
        #url_list列表里都没有返回404
        return '404'
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

2、使用模板引擎

上一步骤中,对于所有的login、index均返回给用户浏览器一个简单的字符串,在现实的Web请求中一般会返回一个复杂的符合HTML规则的字符串,所有我们一般将要返回给用户的HTML写在指定的文件中,然后在返回。

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Index</h1> </body>
</html>

index.html

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<input type="text" />
<input type="text" />
<input type="submit" />
</form>
</body>
</html>

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
#-*- coding:utf-8 -*-
 
from wsgiref.simple_server import make_server
 
 
def index():
    #读取html并返回
    data = open('html/index.html').read()
    return data
 
def login():
    #读取html并返回
    data = open('html/login.html').read()
    return data
 
 
#1 定义一个列表,上面定义函数
url_list = [
    #这里吧URL和函数做一个对应
    ('/index/',index),
    ('/login/',login),
]
 
 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    #根据url的不同,返回不同的字符串
    #1 获取URL[URL从哪里获取?当请求过来之后执行RunServer,wsgi给咱们封装了这些请求,这些请求都封装到了,environ & start_response]
    request_url = environ['PATH_INFO']
    #2 根据URL做不同的相应
    #print environ #这里可以通过断点来查看它都封装了什么数据
 
    #循环这个列表
    for url in url_list:
        #如果用户请求的url和咱们定义的rul匹配
        if request_url == url[0]:
            print url
            return url[1]()
            #执行里面的方法
    else:
        #url_list列表里都没有返回404
        return '404'
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()

对于上述代码,虽然可以返回给用户HTML的内容以现实复杂的页面,但是还是存在问题:如何给用户返回动态的内容呢?

  • 自定义一套特殊的语法,进行转换;

  • 使用开源工具jinja2,遵循其指定语法。

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>{{name}}</h1> <ul>
{% for item in user_list %}
<li>{{item}}</li>
{% endfor %}
</ul> </body>
</html>

index.html

#!/usr/bin/env python
#-*- coding:utf-8 -*- import time
from wsgiref.simple_server import make_server
from jinja2 import Template def index():
data = open('html/index.html').read() template = Template(data)
result = template.render(
name = 'luotianshuai',
age = '18',
time = str(time.time()),
user_list = ['tianshuai','tim','shuaige'],
num = 1
) #同样是替换为什么用jinja,因为他不仅仅是文本的他还支持if判断 & for循环 操作 #这里需要注意因为默认是的unicode的编码所以设置为utf-8
return result.encode('utf-8') def login():
#读取html并返回
data = open('html/login.html').read()
return data #1 定义一个列表,上面定义函数
url_list = [
#这里吧URL和函数做一个对应
('/index/',index),
('/login/',login),
] def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
#根据url的不同,返回不同的字符串
#1 获取URL[URL从哪里获取?当请求过来之后执行RunServer,wsgi给咱们封装了这些请求,这些请求都封装到了,environ & start_response]
request_url = environ['PATH_INFO']
#2 根据URL做不同的相应
#print environ #这里可以通过断点来查看它都封装了什么数据 #循环这个列表
for url in url_list:
#如果用户请求的url和咱们定义的rul匹配
if request_url == url[0]:
print url
return url[1]()
#执行里面的方法
else:
#url_list列表里都没有返回404
return '404' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

遵循jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容。

参考资料:

初识Web框架的更多相关文章

  1. web框架-(一)初识web框架

    一.web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python #coding:ut ...

  2. Web框架的原理和Django初识

    一.Web框架的本质 1.本质 实际上Web应用本质上就是一个socket服务端, 而用户的浏览器就是一个socket客户端. 2.最原始的web框架 socket服务端 import socket ...

  3. Flask(1)- 主流web框架、初识flask

    一.Python 现阶段三大主流Web框架 Django.Tornado.Flask 对比 Django 主要特点是大而全,集成了很多组件(例如Models.Admin.Form等等), 不管你用得到 ...

  4. web框架--tornado框架之初识

    在python中常见的web框架构建模式有以下两种: *MVC框架: * 数据库相关操作的Models 视图文件的Views 业务逻辑的Controllers MTV框架: 数据库相关操作的Model ...

  5. web框架之初识Django

    目录 一.web框架 1.1什么是web框架 1.2自制的简易web框架 1.3三大主流web框架简介 Django Flask Tornado 1.4动态网页与静态网页 二.初识Django框架 2 ...

  6. python web框架——初识tornado

    一 Tornado概述 Tornado是FriendFeed使用的可扩展的非阻塞式web框架及其相关工具的开源版本.这个Web框架看起来有些像web.py或者Google的 webapp,不过为了能有 ...

  7. 初识DJango——Web框架

    一.Web框架 HTTP特点 1.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.POST.每种方法规定了客户与服务器联系的类型不同. 由于HTTP协议简单 ...

  8. Web 应用 WEB框架 HTTP协议 初识Django

    ----------------------------财富存在于人的思想里,你没找到路,不等于没有路,你想知道将来要得到什么,你必须知道现在应该先做什么和先放弃什么! [web 应用] web应用 ...

  9. Go实战--也许最快的Go语言Web框架kataras/iris初识(basic认证、Markdown、YAML、Json)

    ris自称是Go语言中所有Web框架最快的,它的特点如下: 1.聚焦高性能 2.健壮的静态路由支持和通配符子域名支持. 3.视图系统支持超过5以上模板 4.支持定制事件的高可扩展性Websocket ...

随机推荐

  1. Python while 1 和 while True 速度比较

    References http://legacy.python.org/dev/peps/pep-0285/http://stackoverflow.com/questions/3815359/whi ...

  2. h5-21-文件操作-读取文件内容

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. css新奇技术及其未来发展

    1.图像替换技术: 图像替换技术是指使用图像替换页面中文本的功能,类似与在页面中插入图像,只是这种方法更为方便,易于代码管理.通常来说,设计者习惯使用有意义的图像去替换一些标题,logo和某些特定的页 ...

  4. Spark MLlib编程API入门系列之特征选择之卡方特征选择(ChiSqSelector)

    不多说,直接上干货! 特征选择里,常见的有:VectorSlicer(向量选择) RFormula(R模型公式) ChiSqSelector(卡方特征选择). ChiSqSelector用于使用卡方检 ...

  5. Setting up IPS/inline for Linux in Suricata

    不多说,直接上干货! 见官网 https://suricata.readthedocs.io/en/latest/setting-up-ipsinline-for-linux.html Docs » ...

  6. Jquary基础

    基本知识: 就是一个JS函数包 选择器:基本选择器: 基本:ID选择器 “#” , Class选择器 “.”,标签选择器 “标签名” 组合:并列用“,”隔开   后代用空格隔开 过滤选择器:基本过滤: ...

  7. RabbitMQ八:交换机类型Exchange Types--Topic介绍

    前言 上一章节,我们说了两个类型,本章我们说一下其三:Topic Exchange Topic Exchange  Topic Exchange – 将路由键和某模式进行匹配.此时队列需要绑定要一个模 ...

  8. java设计模式之单例设计模式

    单例设计模式 保证一个类在使用过程中,只有一个实例.优势就是他的作用,这个类永远只有一个实例. 优势:这个类永远只有一个实例,占用内存少,有利于Java垃圾回收. 单例设计模式关键点 私有的构造方法. ...

  9. AndroidStudio碰到的各种问题

    源码已经下载了,但是为毛关联不了? 我的源码默认是下载在Sdk\sources\android-23\目录下面的,以前开发的时候都是自动关联的,今天碰到了怎么刷新,怎么关联都不行. 解决方式为: 1. ...

  10. 定时器、线程queue、进程池和线程池

    1.定时器 指定n秒后,执行任务 from threading import Timer,current_thread import os def hello(): print("%s he ...