认识Web应用框架
Web应用框架
Web应用框架(Web application framework)是一种开发框架,用来支持动态网站、网络应用程序及网络服务的开发。类型可以分为基于请求(request-based)的和基于组件(component-based)的两种Web框架。(--来源:百度词条 )
应用:有助于减轻网页开发时共通性活动的工作负荷,例如很多框架提供数据库访问接口、标准样板以及会话管理等,可提升代码的可再用性。(--来源:百度词条 )
Web应用本质上就是一个socket服务端,用户的浏览器是一个socket客户端,基于此,可自定义一个简易版Web框架
'''
自定义的简易版Web框架
'''
import socket
from socket import SOL_SOCKET
from socket import SO_REUSEADDR
# 获取socket对象server
server = socket.socket()
# 允许该端口可以多次运行
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 设置服务端的IP和端口
server.bind((
'127.0.0.1',
9527
))
# 设置半连接池
server.listen(5)
while True:
# 等待客户端访问,当前是阻塞状态,直到有客户端访问
conn, addr = server.accept()
# 接收客户端发送的数据
data = conn.recv(1024)
# 打印客户端发送的请求数据
print(data)
# 向客户端发送响应的数据
conn.send(b'hello world')
# 关闭连接
conn.close()
自定义的web框架服务端已完成,通过浏览器访问 127.0.0.1:9527
,会发现这个页面根本不能正常工作。
我们都知道B/S架构基于浏览器访问服务端的时候,需要遵循HTTP协议,因为HTTP协议规定了客户端和服务端之间的通信格式,那么用户在浏览器输入 https:\\127.0.0.1:9527
,服务端接收到的请求数据什么
在此之前,首先学习下HTTP协议
了解了HTTP协议后,如果想要server端给予响应,必须让server端在给客户端回复消息的时候按照HTTP协议的规则加上响应状态行
while True:
# 等待客户端访问,当前是阻塞状态,直到有客户端访问
conn, addr = server.accept()
# 接收客户端发送的数据
data = conn.recv(1024)
# 在向客户端发送响应数据前,必须加上响应状态行
# HTTP/1.1:协议版本号 200 OK:状态码,200表示客户端请求成功 \r\n\r\n:空行
conn.send(b'HTTP/1.1 200 OK \r\n\r\n')
# 向客户端发送响应的数据,即响应体
conn.send(b'hello world')
# 关闭连接
conn.close()
加上响应状态行后,重新访问 https:\\127.0.0.1:9527
,则浏览器可以收到服务端返回的 hello world
- 第一次优化
如果想要Web服务根据用户请求的URL不同,返回不同的内容,实现思路:首先得拿到这个URL,然后根据URL判断,进而返回不同的内容给浏览器
while True:
# 等待客户端访问,当前是阻塞状态,直到有客户端访问
conn, addr = server.accept()
# 接收客户端发送的数据
data = conn.recv(1024)
print(data)
# 在向客户端发送响应数据前,必须加上响应状态行
conn.send(b'HTTP/1.1 200 OK \r\n\r\n')
path_info = data.decode('utf-8').split('\r\n')[0].split()[1]
print(path_info)
# 根据不同的路径向客户端发送响应的数据
if path_info == '/index':
conn.send(b'from index')
elif path_info == '/login':
conn.send(b'from login')
else:
conn.send(b'404 error')
# 关闭连接
conn.close()
函数版
# 访问index页面调用的函数
def index(url):
return f'from [{url}]file'
# 访问login页面调用的函数
def login(url):
return f'from [{url}]file'
# 创建访问页面路径和函数的对应关系
url_list = [
('/index/', index),
('/login/', login)
]
while True:
# 等待客户端访问,当前是阻塞状态,直到有客户端访问
conn, addr = server.accept()
# 接收客户端发送的数据
data = conn.recv(1024)
# 在向客户端发送响应数据前,必须加上响应状态行
conn.send(b'HTTP/1.1 200 OK \r\n\r\n')
path_info = data.decode('utf-8').split('\r\n')[0].split()[1]
# 根据不同的路径向客户端发送响应的数据
# if path_info == '/index':
# conn.send(b'from index')
# elif path_info == '/login':
# conn.send(b'from login')
# else:
# conn.send(b'404 error')
# 函数版
func = None
# 遍历访问页面路径是否在列表中
for line in url_list:
if line[0] == path_info:
func = line[1]
# 请求页面路径不在列表中,返回404响应
if not func:
res = '404 error'
else:
res = func(path_info)
conn.send(res.encode('utf-8'))
# 关闭连接
conn.close()
- 第二次优化
如果想要根据用户请求的URL不同,返回不同的HTML页面
# 访问index页面调用的函数
def index():
# 读取index.html页面中的内容
with open(r'E:\Oldboy\python3\200103自定义Web框架\templates\index.html',
'r', encoding='utf-8') as f:
data = f.read()
# return f'from [{url}]file'
return data
# 访问login页面调用的函数
def login():
with open(r'E:\Oldboy\python3\200103自定义Web框架\templates\login.html',
'r', encoding='utf-8') as f:
data = f.read()
# return f'from [{url}]file'
return data
# 创建访问页面路径和函数的对应关系
url_list = [
('/index/', index),
('/login/', login)
]
while True:
# 等待客户端访问,当前是阻塞状态,直到有客户端访问
conn, addr = server.accept()
# 接收客户端发送的数据
data = conn.recv(1024)
# 在向客户端发送响应数据前,必须加上响应状态行
conn.send(b'HTTP/1.1 200 OK \r\n\r\n')
path_info = data.decode('utf-8').split('\r\n')[0].split()[1]
# 根据不同的路径向客户端发送响应的数据
# if path_info == '/index':
# conn.send(b'from index')
# elif path_info == '/login':
# conn.send(b'from login')
# else:
# conn.send(b'404 error')
# 函数版
func = None
# 遍历访问页面路径是否在列表中
for line in url_list:
if line[0] == path_info:
func = line[1]
# 请求页面路径不在列表中,返回404响应
if not func:
res = '404 error'
else:
res = func()
conn.send(res.encode('utf-8'))
# 关闭连接
conn.close()
- 第三次优化,不再自己手动创建套接字服务端,使用wsgiref模块
from wsgiref.simple_server import make_server
import urls
import views
def run(env, response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return: 浏览器能够接受的内容
"""
response('200 OK', [])
# print(env) # 是一个字典,其中PATH_INFO这个键值对存储的就是用户请求的url
target_url = env.get('PATH_INFO')
# 定义变量,存储可能匹配的函数,不直接调用是因为有可能请求的路径不存在
func = None
for line in urls.url_list:
if line[0] == target_url:
# 符合条件,说明后端已设置对应的页面数据,赋给func
func = line[1]
# 找到后,跳出循环,没必要继续查找
break
# 最后都没有找到,说明请求无效
if not func:
# 调用404页面
res = views.error(env)
else:
res = func(env)
# 将响应页面的数据返回给浏览器,展示给用户
return [res.encode('utf-8')]
if __name__ == '__main__':
# 监听host:port,一旦有客户端(浏览器)访问,立即执行第三个参数(可以是类)
server = make_server('127.0.0.1', 9527, run)
# 启动服务端
server.serve_forever()
了解一下
参照:
https://www.leiue.com/what-is-wsgi
https://blog.csdn.net/laughing2333/article/details/51288660
https://cizixs.com/2014/11/09/dive-into-wsgiref/
WSGI和 wsgiref
WSGI(Web Server Gateway Interface) Web服务器网关接口,是专门为Python语言定义的web服务器与Web应用程序或框架之间的一种简单而通用的接口
wsgiref 是一个实现了WSGI标准的范例实现(用于演示的简单python内置库),里面的功能包含了:1.操作wsgi 的环境变量;2.应答头部的处理;3.实现简单的HTTP server;4.简单的程序端和服务端校验函数
- 第四次优化 基于jinja2模块,实现动态网页
# 导入jinja2模块,使用模板语法
from jinja2 import Template
import pymysql
# 使用jinja2 中的模板语法实现动态网页
def userinfo(env):
# 调用数据库中的记录
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='Ad123',
database='django_test',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
sql = 'select * from userinfo'
cursor.execute(sql)
# 返回结果集:[{},{},{}]
data = cursor.fetchall()
# 该函数返回一个html页面
with open(r'E:\Oldboy\python3\200103自定义Web框架\templates\userinfo.html',
'r', encoding='utf-8') as f:
res = f.read()
# 利用jinja2
tmp = Template(res)
# 利用对象的render 方法,将从数据库的结果集传给html页面
res = tmp.render(xxx=data)
return res
<table class="table table-striped table-hover">
<thead>
<tr>
<th>序号</th>
<th>username</th>
<th>password</th>
</tr>
</thead>
<tbody>
<!--通过jinja2的模板语法,可以直接在html文档中使用python 语法-->
<!--获取到数据集[{},{},{}],遍历结果集-->
{%for user_dict in xxx %}
<!--一个字典(数据库的中一条数据)就是一行记录-->
<tr>
<!--字典中的键值对就是一列-->
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.username }}</td>
<td>{{ user_dict.password }}</td>
</tr>
{% endfor %}
</tbody>
</table>*
了解一下
参照: https://baike.baidu.com/item/jinja2/8911090?fr=aladdin
http://docs.jinkan.org/docs/jinja2/
https://www.jianshu.com/p/f04dae701361
jinja2:基于python的模板引擎,其设计思想来源于django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的一个是增加了沙箱执行功能和可选的自动转义功能。
特点:
- 沙箱中执行
- 强大的HTML自动转义系统,可以有效地组织跨站脚本攻击(XSS,利用网站漏铜从用户那里恶意盗取信息)
- 模板继承机制,此机制可以使得所有的模板都具有相似一致的布局, 方便了开发人员对模板的修改和管理
- 高效的执行效率,Jinja2引擎在模板第一次加载时就把源码转换成Python字节码,加快模板执行时间。
- 可选的预编译模式
- 易于调试。异常的行数直接指向模板中的对应行
- 可配置的语法
语法
- 控制结构 {% %}
- 变量取值 {{ }}
jinja2模板中使用{{ }} 语法表示一个变量,是一种特殊的占位符。当利用jinja2进行渲染的时候,它会把这些特殊的占位符进行填充/替换,jinja2支持python中所有数据类型,如列表、字段、对象等
- 注释 {# #}
认识Web应用框架的更多相关文章
- React 还是 Vue: 你应该选择哪一个Web前端框架?
学还是要学的,用的多了,也就有更多的认识了,开发中遇到选择的时候也就简单起来了. 本文作者也做了总结: 如果你喜欢用(或希望能够用)模板搭建应用,请使用Vue 如果你喜欢简单和“能用就行”的东西 ...
- 学习ASP.NET Web API框架揭秘之“HTTP方法重写”
最近在看老A的<ASP.NET Web API 框架揭秘>,这本书对于本人现阶段来说还是比较合适的(对于调用已经较为熟悉,用其开发过项目,但未深入理解过很多内容为何可以这样“调用”).看到 ...
- L20n – Mozilla 推出的 Web 本地化框架
L20n是 Mozilla 开发的用于 Web 开发的本地化框架.它允许本地化开发者把逻辑细分为本地化的资源. L20n 的框架不再需要开发人员深入理解自然语言的具体细节,并提供了机会为本地化创造更好 ...
- tornado 学习笔记2 Python web主流框架
2.1 Django 官方网址:https://www.djangoproject.com/ 简介:Django is a high-level Python Web framework that e ...
- 【转】谈谈Google Polymer以及Web UI框架的未来
原文转自:http://www.csdn.net/article/2013-05-27/2815450-google-polymer 摘要:开发者Axel Rauschmayer在自己的博客上详解了G ...
- Spring 4 官方文档学习(十一)Web MVC 框架之配置Spring MVC
内容列表: 启用MVC Java config 或 MVC XML namespace 修改已提供的配置 类型转换和格式化 校验 拦截器 内容协商 View Controllers View Reso ...
- Node.js简单介绍并实现一个简单的Web MVC框架
编号:1018时间:2016年6月13日16:06:41功能:Node.js简单介绍并实现一个简单的Web MVC框架URL :https://cnodejs.org/topic/4f16442cca ...
- Web自动化框架LazyUI使用手册(2)--先跑起来再说(第一个测试用例-百度搜索)
作者:cryanimal QQ:164166060 上篇文章中,简要介绍了LazyUI框架,本文便来演示,如何从无到有快速搭建基于lazyUI的工程,并成功运行第一个测试用例. 本文以百度搜索为例,选 ...
- 【JavaScript】谈谈Google Polymer以及Web UI框架的未来
摘要:开发者Axel Rauschmayer在自己的博客上详解了Google Polymer的设计理念与组成架构,深得Polymer开发者的认同.他认为Polymer这样高互操作性的设计才应该是Web ...
- node.js Web应用框架Express.js(一)
什么是Express.js Express 是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用,提供丰富的HTTP工具以及来自Connect框架的中间件随 ...
随机推荐
- 2019-7-1-VisualStudio-快速设置启动项目
title author date CreateTime categories VisualStudio 快速设置启动项目 lindexi 2019-07-01 14:37:38 +0800 2019 ...
- Open Source GIS and Freeware GIS Applications
Open Source GIS and Freeware GIS Applications An open source application by definition is software ...
- Oracle使用——varchar2() 和 char()关联查询 存在空格
背景 表dbcontinfo 字段loanid,类型为varchar2(60) 表dbloanbal 字段loanid,类型为char(60) loanid字段实际长度为24位 问题 两张表dbloa ...
- eclipse maven项目导出所使用的jar包
在eclipse中定位到maven项目的pom.xml文件右击pom.xml文件,选择Run As-->Maven build…在打开的页面中,GOLAS栏输入“dependency:copy- ...
- 原生js实现计时器
https://www.cnblogs.com/sandraryan/ 点击开始计时,可以计次,暂停.点了暂停可以继续计时,计次,点击重置清空. <!DOCTYPE html> <h ...
- 用winrar和zip命令拷贝目录结构
linux系统下使用zip命令 zip -r source.zip source -x *.php -x *.html # 压缩source目录,排除里面的php和html文件 windows系统下使 ...
- Fragment学习(二): 管理Fragment和Fragment通讯
一. 管理Fragment 首先,如果你想在Android3.0及以下版本使用Fragment,你必须引用android-support-v4.jar这个包 然后你写的activity不能再继承自Ac ...
- Python--day70--csrf简单用法、 跨站请求伪造和csrf_token使用
1,csrf简单用法 2,Django里面的setting加入了防跨站伪造:这段代码帮你生成特殊字符串,帮你塞到html页面中来 3,csrf_token使用:
- set_time_limit(0)是什么意思?
语法 : void set_time_limit (int seconds) 说明 : 设定一个程式所允许执行的秒数,如果到达限制的时间,程式将会传回错误.它预设的限制时间是30秒,max_execu ...
- 4-10 items设计
1,items相当于dict,但是又比字典好 2,parse.urljoin(response.url,post_url)方法,其中image_url是一个域名的话,其中的当前域名就不用再添加. yi ...