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应用框架的更多相关文章

  1. React 还是 Vue: 你应该选择哪一个Web前端框架?

    学还是要学的,用的多了,也就有更多的认识了,开发中遇到选择的时候也就简单起来了. 本文作者也做了总结: 如果你喜欢用(或希望能够用)模板搭建应用,请使用Vue    如果你喜欢简单和“能用就行”的东西 ...

  2. 学习ASP.NET Web API框架揭秘之“HTTP方法重写”

    最近在看老A的<ASP.NET Web API 框架揭秘>,这本书对于本人现阶段来说还是比较合适的(对于调用已经较为熟悉,用其开发过项目,但未深入理解过很多内容为何可以这样“调用”).看到 ...

  3. L20n – Mozilla 推出的 Web 本地化框架

    L20n是 Mozilla 开发的用于 Web 开发的本地化框架.它允许本地化开发者把逻辑细分为本地化的资源. L20n 的框架不再需要开发人员深入理解自然语言的具体细节,并提供了机会为本地化创造更好 ...

  4. tornado 学习笔记2 Python web主流框架

    2.1 Django 官方网址:https://www.djangoproject.com/ 简介:Django is a high-level Python Web framework that e ...

  5. 【转】谈谈Google Polymer以及Web UI框架的未来

    原文转自:http://www.csdn.net/article/2013-05-27/2815450-google-polymer 摘要:开发者Axel Rauschmayer在自己的博客上详解了G ...

  6. Spring 4 官方文档学习(十一)Web MVC 框架之配置Spring MVC

    内容列表: 启用MVC Java config 或 MVC XML namespace 修改已提供的配置 类型转换和格式化 校验 拦截器 内容协商 View Controllers View Reso ...

  7. Node.js简单介绍并实现一个简单的Web MVC框架

    编号:1018时间:2016年6月13日16:06:41功能:Node.js简单介绍并实现一个简单的Web MVC框架URL :https://cnodejs.org/topic/4f16442cca ...

  8. Web自动化框架LazyUI使用手册(2)--先跑起来再说(第一个测试用例-百度搜索)

    作者:cryanimal QQ:164166060 上篇文章中,简要介绍了LazyUI框架,本文便来演示,如何从无到有快速搭建基于lazyUI的工程,并成功运行第一个测试用例. 本文以百度搜索为例,选 ...

  9. 【JavaScript】谈谈Google Polymer以及Web UI框架的未来

    摘要:开发者Axel Rauschmayer在自己的博客上详解了Google Polymer的设计理念与组成架构,深得Polymer开发者的认同.他认为Polymer这样高互操作性的设计才应该是Web ...

  10. node.js Web应用框架Express.js(一)

    什么是Express.js Express 是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用,提供丰富的HTTP工具以及来自Connect框架的中间件随 ...

随机推荐

  1. 待性能改善的一个SQL

    select t.*, t.rowid from tb_tk_datasakusei_ctrl t; alter table ATOMBB.TB_TK_JISSEKI_INFO_DETAIL add ...

  2. oracle函数 COALESCE(c1, c2, ...,cn)

    [功能]返回列表中第一个非空的表达式,如果所有表达式都为空值则返回1个空值 [参数]c1, c2, ...,cn,字符型/数值型/日期型,必须类型相同或null [返回]同参数类型 [说明]从Orac ...

  3. oracle函数 TRIM(c1 from c2)

    [功能]删除左边和右边出现的字符串 [参数]C2 删除前字符串 c1 删除字符串,默认为空格 [返回]字符型 [示例] select TRIM('X' from 'XXXgao qian jingXX ...

  4. Android中使用lambda表达式

    lambda 语法简介 视频为本篇播客知识点讲解,建议采用超清模式观看, 欢迎点击订阅我的优酷 如果刚学Android,不知道怎么写点击事件可以跳转,传送门 要想在Android中使用lambda语法 ...

  5. 原生sql和 TP sql怎么关联?

    整合后

  6. hdu 1026 Ignatius and the Princess I(bfs)

    Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  7. 利用arguments求任意数量数字的和/最大值/最小值

    文章地址 https://www.cnblogs.com/sandraryan/ arguments是函数内的临时数据,用完销毁,有类似于数组的操作,但不是数组. 举个栗子1:利用arguments求 ...

  8. Python--day44--navicat使用(知道怎么用就好,要用终端操作,用这个会被人鄙视)

  9. 【codeforces 766D】Mahmoud and a Dictionary

    time limit per test4 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  10. Xshell + SVN使用

    切换目录 cd+想跳转到的目录下 文件浏览 ls ll (ll 信息全) svn更新 svn up 编辑 vi vi的命令 文件保存与退出: :q 在文件未作任何修改的情况下退出. :q! 强制退出, ...