认识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框架的中间件随 ...
随机推荐
- es6 中let与const的简析
1.let 它的作用类似于var,用来声明变量,但是所声明的变量,只在let命令所在的代码块内有效. if(true){ ; let b = ; } document.write(a); docume ...
- @codeforces - 1187F@ Expected Square Beauty
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个序列 x = {x1, x2, ..., xn},已知 ...
- 异常解决:non-compatible bean definition of same name and class【com.xxx.xxx.XXX】
昨天同事遇到这样一个问题,意思是spring找到 有相同的实现类名在不同的package目录下. 跟踪他的项目代码并未发现问题. 重新给他的maven项目进行maven install一下. 查看 ...
- Java排序算法总结
1.冒泡排序 冒泡排序是排序算法中最基本的一种排序方法,该方法逐次比较两个相邻数据的大小并交换位置来完成对数据排序,每次比较的结果都找出了这次比较中数据的最大项,因为是逐次比较,所以效率是O(N^2) ...
- visual studio 2013 修改mvc5的视图模板
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffol ...
- protobuf DNK下的编译
protobuffer 编译配置 mkdir -p ./cmake/build cd ./cmake/build cmake \ -Dprotobuf_BUILD_SHARED_LIBS=OFF \ ...
- TAE words
love handle pang carbohydrate podiatry splay out Cinderella liposuction mingle fly t ...
- oracle 基础表的选择
基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的. 如果你使用的是CBO (COST BASED OPTI ...
- C# Dapper 基本使用 增删改查事务
来源:https://blog.csdn.net/Tomato2313/article/details/78880969 using DapperTest.Models; using System.C ...
- HMM(隐马尔科夫)用于中文分词
隐马尔可夫模型(Hidden Markov Model,HMM)是用来描述一个含有隐含未知参数的马尔可夫过程. 本文阅读了2篇blog,理解其中的意思,附上自己的代码,共同学习. 一.理解隐马尔科夫 ...