WEB框架的本质

python的WEB框架分为两大类:

1、自己写socket,自己处理请求

2、基于wsgi(Web Server Gateway Interface WEB服务网关接口),自己处理请求

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

看下面的代码是WEB最本质的WEB框架(自己写的socket,自己处理的请求)

#!/usr/bin/env python
#coding:utf-8 import socket def handle_request(client):
#接收请求
buf = client.recv(1024)
#返回信息
client.send("HTTP/1.1 200 OK\r\n\r\n")
client.send("Hello, lili") def main():
#创建sock对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#监听80端口
sock.bind(('localhost',8010))
#最大允许排队的客户端
sock.listen(5) #循环
while True:
#等待用户的连接,默认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 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。python标准库提供的独立WSGI服务器称为wsgiref

#!/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, web!</h1>' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
#接收请求
#预处理请求(封装了很多http请求的东西)  

当请求过来后就执行RunServer这个函数。

OK 下面看WEB框架图(Socket & 处理请求的函数)

这两类WEB框架的区别是一个是自己写socket,一个是基于wsgi。

  • 自己写socket,自己处理请求的代表框架是Tornado(还有就是Tronado有两种模式,可以通过修改配置让它使用自己写的socket也可以基于wsgi)
  • 基于WSGI的WEB框架代表就是django

自定义框架

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

#!/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,django!</h1>' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

当我们访问的时候,访问任何的url都会显示,Hello,django,其他网站则是根据用户输入URL的不同返回给用户不同的html.

既然是根据用户输入的URL的不同来返回不同的内容,我们就需要获取用户的内容。

#!/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')])
#根据url的不同,返回不同的字符串
#1 获取URL[URL从哪里获取?当请求过来之后执行RunServer,wsgi给咱们封装了这些请求,这些请求都封装到了,environ & start_response]
request_url = environ['PATH_INFO']
print request_url
#2 根据URL做不同的相应
#print environ #这里可以通过断点来查看它都封装了什么数据
if request_url == '/home/index':
return "Hello Home"
elif request_url == '/login':
return "welcome to login our site. "
else:
return '<h1>404!</h1>' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever() 

用户的请求少还好,如果比较多使用if这种方式就不可行了,我们可以采用如下方法来实现:

#!/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写在指定文件中,然后再返回。

#index.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Index</h1> </body>
</html>
#login
<!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>
#!/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,遵循其指定语法

index.html  遵循jinja语法进行替换、循环、判断

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--general replace-->
<h1>{{ name }}</h1>
<h1>{{ age }}</h1>
<h1>{{ time }}</h1> <!--for circular replace-->
<ul>
{% for iterm in user_list %}
<li>{{ iterm }}</li>
{% endfor %}
</ul>
<!--if else judge--> {% if num == 1%}
<h1>1111</h1>
{% else %}
<h1>2222</h1>
{% endif %} </body> </html>
#web.py

#!/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的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容,对于模板引擎的本质,参考武Sir老师一篇博客:白话tornado源码之褪去模板外衣的前戏

参考文章:

http://www.cnblogs.com/luotianshuai/p/5258572.html

http://www.cnblogs.com/wupeiqi/articles/5237672.html

python学习之路web框架的更多相关文章

  1. python学习之路web框架续

    中间件 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在django项 ...

  2. Python学习之路-Day1-Python基础

    学习python的过程: 在茫茫的编程语言中我选择了python,因为感觉python很强大,能用到很多领域.我自己也学过一些编程语言,比如:C,java,php,html,css等.但是我感觉自己都 ...

  3. Python学习之路【第一篇】-Python简介和基础入门

    1.Python简介 1.1 Python是什么 相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是 ...

  4. 一、Python学习之路

    基础篇 第一章         Python介绍.安装.使用 Python 简介 Python 安装 第一个Python程序 Python 解释器 字符编码与解码 动态语言与静态语言的区别 变量及简单 ...

  5. Django 2.0 学习(15):Web框架

    Web框架的本质 对于学习Python的同学,相信对Flask.Django.Web.py等不会陌生,这些都是Python语言的web框架.那么问题来了,web服务器是什么?它和web框架有什么关系? ...

  6. python几个轻量级web框架

    python几个轻量级web框架 2016-04-11 18:04:34 惹不起的程咬金 阅读数 7944更多 分类专栏: 云计算/大数据/并行计算 Python   我最近发表了一篇名为 ‘7 Mi ...

  7. python学习之路-day2-pyth基础2

    一.        模块初识 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,第三方库存放位置:site-packages sys模块简介 导入模块 import sys 3 sys模 ...

  8. Python学习之路-Day2-Python基础3

    Python学习之路第三天 学习内容: 1.文件操作 2.字符转编码操作 3.函数介绍 4.递归 5.函数式编程 1.文件操作 打印到屏幕 最简单的输出方法是用print语句,你可以给它传递零个或多个 ...

  9. Python学习之路-Day2-Python基础2

    Python学习之路第二天 学习内容: 1.模块初识 2.pyc是什么 3.python数据类型 4.数据运算 5.bytes/str之别 6.列表 7.元组 8.字典 9.字符串常用操作 1.模块初 ...

随机推荐

  1. RxJava系列6(从微观角度解读RxJava源码)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  2. 读取properties配置的工具类

    @Service public class AppPropertiesManager implements DisposableBean{ @Value("${shortloan_rate_ ...

  3. Android智能手机上的音频浅析

    手机可以说是现在人日常生活中最离不开的电子设备了.它自诞生以来,从模拟的发展到数字的,从1G发展到目前的4G以及不久将来的5G,从最初的只有唯一的功能(打电话)发展到目前的全功能,从功能机(featu ...

  4. 浅谈 Mybatis中的 ${ } 和 #{ }的区别

    好了,真正做开发也差不多一年了.一直都是看别人的博客,自己懒得写,而且也不会写博客,今天就开始慢慢的练习一下写博客吧.前段时间刚好在公司遇到这样的问题. 一.举例说明 select * from us ...

  5. 盒子浮动float

    一.float的基本规律 规律1: 标准流模型中的块级盒子,默认宽度100%: 而浮动的块级盒子,宽度不会自动伸展,而是由内容(文字.padding)撑开: 浮动后的行级元素,可以设置宽度高度等属性. ...

  6. [C#]200 行代码使用 C# 实现区块链

    文章原文来自:Code your own blockchain in less than 200 lines of Go!,原始文章是通过 Go 语言来实现自己的区块链的,这里我们参照该文章来使用 C ...

  7. 属性添加get和set方法

    出错信息: Struts Problem Report Struts has detected an unhandled exception: Messages: File: com/myHibern ...

  8. python 网络爬虫(一)爬取天涯论坛评论

    我是一个大二的学生,也是刚接触python,接触了爬虫感觉爬虫很有趣就爬了爬天涯论坛,中途碰到了很多问题,就想把这些问题分享出来, 都是些简单的问题,希望大佬们以宽容的眼光来看一个小菜鸟

  9. [HNOI2009]通往城堡之路

    题目描述 听说公主被关押在城堡里,彭大侠下定决心:不管一路上有多少坎坷,不管城堡中的看守有多少厉害,不管救了公主之后公主会不会再被抓走,不管公主是否漂亮.是否会钟情于自己,他将义无反顾地朝着城堡前进. ...

  10. 洛谷P3164 [CQOI2014]和谐矩阵

    高斯消元,可以直接消的 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cst ...