一  Web框架本质

1. 自己开发Web框架
- socket
- http协议
- HTML知识
- 数据库(pymysql,SQLAlchemy) HTTP:
无状态、短连接 TCP:
不断开 WEB应用(网站):
Http协议:
发送:
POST /index HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36
HTTPS: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: csrftoken=hNmu2JOtntGMN0hSRSPmMQk2newEb3o8zb6pXW5Cc3m54IaA5VlTkUvqWsFezpni p=123 响应:
200 OK
Cache-Control:public, max-age=15
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html; charset=utf-8
Date:Wed, 14 Jun 2017 01:21:17 GMT
Expires:Wed, 14 Jun 2017 01:21:33 GMT
Last-Modified:Wed, 14 Jun 2017 01:21:03 GMT
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Frame-Options:SAMEORIGIN
X-UA-Compatible:IE=10 用户在页面看到的内容“字符串”(看到页面效果,由于浏览器解析) 浏览器(socket客户端)
2. www.cnblogs.com(42.121.252.58,80)
sk.socket()
sk.connect((42.121.252.58,80)) sk.send('我想要xx')
5. 接收
6. 连接断开 博客园(socket服务端)
1. 监听ip和端口(42.121.252.58,80)
while True:
用户 = 等待用户连接
3. 收到'我想要xx'
4. 响应:“好”
用户断开 import socket sock = socket.socket()
sock.bind(('127.0.0.1',8080))
sock.listen(5) while True:
conn,addr = sock.accept() # hang住
# 有人来连接了
# 获取用户发送的数据
data = conn.recv(8096)
conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
conn.send(b'')
conn.close() 1. Http,无状态,短连接
2.
浏览器(socket客户端)
网站(socket服务端) 3. 自己写网站
a. socket服务端
b. 根据URL不同返回不同的内容
路由系统:
URL -> 函数
c. 字符串返回给用户
模板引擎渲染:
HTML充当模板(特殊字符)
自己创造任意数据
字符串 4. Web框架:
框架种类:
- a,b,c --> Tornado
- [第三方a],b,c --> wsgiref -> Django
- [第三方a],b,[第三方c] --> flask, 分类:
- Django框架(Web。。。。。。)
- 其他

web 框架本质

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

import socket

def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 200 OK\r\n\r\n")
client.send("Hello, Seven") def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost',8000))
sock.listen(5) while True:
connection, address = sock.accept()
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。

from wsgiref.simple_server import make_server

def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ] if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print("Serving HTTP on port 8000...")
httpd.serve_forever()

二  自定义Web框架

框架

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

#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server def index():
return 'index' def login():
return 'login' def routers(): urlpatterns = (
('/index/',index),
('/login/',login),
) return urlpatterns def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8000, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

模板引擎

在上一步骤中,对于所有的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.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>
#!/usr/bin/env python
# -*- coding:utf-8 -*- from wsgiref.simple_server import make_server def index():
# return 'index'
f = open('index.html')
data = f.read()
return data def login():
# return 'login'
f = open('login.html')
data = f.read()
return data def routers(): urlpatterns = (
('/index/', index),
('/login/', login),
) return urlpatterns def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8000, run_server)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

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

  • 1)自定义一套特殊的语法,进行替换
  • 2)使用开源工具jinja2,遵循其指定语法

index.html

<!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>
#!/usr/bin/env python
# -*- coding:utf-8 -*- from wsgiref.simple_server import make_server
from jinja2 import Template def index():
# return 'index' # template = Template('Hello {{ name }}!')
# result = template.render(name='John Doe') f = open('index.html')
result = f.read()
template = Template(result)
data = template.render(name='John Doe', user_list=['alex', 'eric'])
return data.encode('utf-8') def login():
# return 'login'
f = open('login.html')
data = f.read()
return data def routers(): urlpatterns = (
('/index/', index),
('/login/', login),
) return urlpatterns def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return '404 not found' if __name__ == '__main__':
httpd = make_server('', 8000, run_server)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

遵循jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容,对于模板引擎的本质

三  自己开发web框架

实现静态网站

import socket

def f1(request):
"""
处理用户请求,并返回相应的内容
:param request: 用户请求的所有信息
:return:
"""
f = open('index.fsw','rb')
data = f.read()
f.close()
return data def f2(request):
f = open('aricle.tpl','r',encoding='utf-8')
data = f.read()
f.close()
import time
ctime = time.time()
data = data.replace('@@sw@@',str(ctime))
return bytes(data,encoding='utf-8') def f3(request):
import pymysql # 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='db666')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,username,password from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close() content_list = []
for row in user_list:
tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password'])
content_list.append(tp)
content = "".join(content_list) f = open('userlist.html','r',encoding='utf-8')
template = f.read()
f.close() # 模板渲染(模板+数据)
data = template.replace('@@sdfsdffd@@',content)
return bytes(data,encoding='utf-8') def f4(request):
import pymysql # 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='db666')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,username,password from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close() f = open('hostlist.html','r',encoding='utf-8')
data = f.read()
f.close() # 基于第三方工具实现的模板渲染
from jinja2 import Template
template = Template(data)
data = template.render(xxxxx=user_list,user='sdfsdfsdf')
return data.encode('utf-8') routers = [
('/xxx', f1),
('/ooo', f2),
('/userlist.htm', f3),
('/host.html', f4),
] def run():
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1',8080))
sock.listen(5) while True:
conn,addr = sock.accept() # hang住
# 有人来连接了
# 获取用户发送的数据
data = conn.recv(8096)
data = str(data,encoding='utf-8')
headers,bodys = data.split('\r\n\r\n')
temp_list = headers.split('\r\n')
method,url,protocal = temp_list[0].split(' ')
conn.send(b"HTTP/1.1 200 OK\r\n\r\n") func_name = None
for item in routers:
if item[0] == url:
func_name = item[1]
break if func_name:
response = func_name(data)
else:
response = b"" conn.send(response)
conn.close() if __name__ == '__main__':
run()

s1.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>用户登录</h1>
<form>
<p><input type="text" placeholder="用户名" /></p>
<p><input type="password" placeholder="密码" /></p>
</form>
</body>
</html> index.fsw

index.fsw

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<th>root</th>
<th>root@qq.com</th>
</tr>
</tbody>
</table>
</body>
</html> aricle.tpl

aricle.tpl

实现动态网站

import socket

def f1(request):
"""
处理用户请求,并返回相应的内容
:param request: 用户请求的所有信息
:return:
"""
f = open('index.fsw','rb')
data = f.read()
f.close()
return data def f2(request):
f = open('aricle.tpl','r',encoding='utf-8')
data = f.read()
f.close()
import time
ctime = time.time()
data = data.replace('@@sw@@',str(ctime))
return bytes(data,encoding='utf-8') def f3(request):
import pymysql # 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='db666')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,username,password from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close() content_list = []
for row in user_list:
tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password'])
content_list.append(tp)
content = "".join(content_list) f = open('userlist.html','r',encoding='utf-8')
template = f.read()
f.close() # 模板渲染(模板+数据)
data = template.replace('@@sdfsdffd@@',content)
return bytes(data,encoding='utf-8') def f4(request):
import pymysql # 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='db666')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,username,password from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close() f = open('hostlist.html','r',encoding='utf-8')
data = f.read()
f.close() # 基于第三方工具实现的模板渲染
from jinja2 import Template
template = Template(data)
data = template.render(xxxxx=user_list,user='sdfsdfsdf')
return data.encode('utf-8') routers = [
('/xxx', f1),
('/ooo', f2),
('/userlist.htm', f3),
('/host.html', f4),
] def run():
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1',8080))
sock.listen(5) while True:
conn,addr = sock.accept() # hang住
# 有人来连接了
# 获取用户发送的数据
data = conn.recv(8096)
data = str(data,encoding='utf-8')
headers,bodys = data.split('\r\n\r\n')
temp_list = headers.split('\r\n')
method,url,protocal = temp_list[0].split(' ')
conn.send(b"HTTP/1.1 200 OK\r\n\r\n") func_name = None
for item in routers:
if item[0] == url:
func_name = item[1]
break if func_name:
response = func_name(data)
else:
response = b"" conn.send(response)
conn.close() if __name__ == '__main__':
run() s1.py

s1.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>用户登录</h1>
<form>
<p><input type="text" placeholder="用户名" /></p>
<p><input type="password" placeholder="密码" /></p>
</form>
</body>
</html> index.fsw

index.fsw

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<th>@@sw@@</th>
<th>root@qq.com</th>
</tr>
</tbody>
</table>
</body>
</html> aricle.tpl

aricle.tpl

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
{% for row in xxxxx %}
<tr>
<td>{{row.id}}</td>
<td>{{row.username}}</td>
<td>{{row.password}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{user}}
</body>
</html> userlist.html

userlist.htmlWeb

Web 框架本质解析的更多相关文章

  1. WEB框架本质和第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 总的来说:Web框架的本质就是浏览 ...

  2. Django框架01 / http协议、web框架本质

    Django框架01 / http协议.web框架本质 目录 Django框架01 / http协议.web框架本质 1.http协议 1.1 http协议简介 1.2 什么是http协议 1.3 H ...

  3. Python开发【第十四篇】:Web框架本质

    Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

  4. Web框架本质

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

  5. Python自动化运维之26、Web框架本质、MVC与MTV

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

  6. Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  7. Web框架本质及第一个Django实例 Web框架

    Web框架本质及第一个Django实例   Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web ...

  8. Django之Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  9. Django框架----Web框架本质

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

随机推荐

  1. spring学习笔记(五)

    1.后置通知 需求:调用相应业务方法后,完成资源的关闭. a. 在beans.xml中配置 .... <beans> <!--配置被代理对象--> <bean id=&q ...

  2. C# 读取Ini配置文件类

    配置文件 为fileName.ini 的文件 第一行必须为空,不然读不出值 [section1] key=value key2=value ......... [section2] key=value ...

  3. 深入理解Tomcat虚拟文件夹

        我们知道,Web站点中的内容(包含网页,图片,音频文件等)一般都存放在App的文件夹下.但随着站点内容的不断丰富,用户须要把不同层次的内容组织成站点的子文件夹. 我们通常的做法是在站点主文件夹 ...

  4. Hive学习 系列博客

    原 Hive作业优化 原 Hive学习六:HIVE日志分析(用户画像) 原 Hive学习五--日志案例分析 原 Hive学习三 原 Hive学习二 原 Hive学习一 博客来源,https://blo ...

  5. Redis(四):常用数据类型和命令

    命令手册网址 http://doc.redisfans.com/ Redis数据类型 l String l Hash l List l Set l Sorted Set Redis中还有3种特殊的数据 ...

  6. Atitit. atiOrder   Order 订单管理框架的设计

    Atitit. atiOrder   Order 订单管理框架的设计 1. Order 订单处理流程1 2. code2 3. Ref7 1. Order 订单处理流程 if(userSvr.isNo ...

  7. spring security 3.1 实现权限控制

    spring security 3.1 实现权限控制 简单介绍:spring security 实现的权限控制,能够分别保护后台方法的管理,url连接訪问的控制,以及页面元素的权限控制等, secur ...

  8. mock实例方法

    1.Mockito.when(categoryService.queryTopCategory("1")).thenReturn(categories);//返回的是list列表, ...

  9. 在 Windows 上安装 TensorFlow(转载)

    在 Windows 上安装 TensorFlow windows下配置安装Anaconda+tensorflow Spyder——科学的Python开发环境 Windows7 安装TensorFlow ...

  10. CI框架基本配置/教你学习CI框架codelgniter

    CI框架现在中国可以说还是不成熟,不像thinkphp那样有那么多的中文手册,在国内,很多国人英语都很烂,CI现在教程还是不多.大家心里都存在这严重想法 CI 框架现在中国可以说还是不成熟,不像thi ...