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. Android ListView显示底部的分割线

    有些时候,我们会提出这样的需求,希望ListView显示底部(顶部)的分割线,这样做,会使得UI效果更加精致,如下图所示: 如果搜索资料,大家会搜到一堆相关的方法,最多的莫过于设置listview的f ...

  2. oracle函数 exp(y)

    [功能]返回e的y次幂(e为数学常量) [参数]y,数字型表达式 [返回]数字 [示例] select exp(3),exp(0),exp(-3) from dual; 返回:20.0855369,1 ...

  3. 怎么查看mysql 的binlog日志存放的位置

    image.png 这个你可以看配置文件 启用了才有这样的记录默认是没有的 linux系统中的/etc/my.cnf my.cnf内容: log-bin = mysqlbin # 默认配置 一般放在/ ...

  4. jqLite

    一.关于DOM导航的jqLite方法 children() 返回一组子元素.这个方法的jqLite实现不支持jQuery所提供的选择器特性 eq(index) 从一个元素集合中返回指定索引下的元素 f ...

  5. Project Euler Problem 5-Smallest multiple

    对每个数字分解素因子,最后对每个素因子去其最大的指数,然后把不同素因子的最大指数次幂相乘,得到的就是最小公倍数 python不熟练,代码比较挫 mp = {} def process(n): i = ...

  6. Python 函数参数有冒号 声明后有-> 箭头 返回值注释 参数类型注释

    在python3.7 环境下 函数声明时能在参数后加冒号,如图: 1 def f(ham: str, eggs: str = 'eggs') -> str : 2 print("Ann ...

  7. jar包运行

    配置mainClass:            <plugin>                <groupId>org.apache.maven.plugins</gr ...

  8. LEMP--如何在Ubuntu上安装Linux、Nginx、MySQL和PHP

    简介 LEMP是用来搭建动态网站的一组软件,首字母缩写分别表示Linux.Nginx(Engine-X).MySQL和PHP. 本文将讲述如何在Ubuntu安装LEMP套件.当然,首先要安装Ubunt ...

  9. JQuery操作select下拉框

    JQuery操作select下拉框 获取Select选择的Text和Value $("#select_id").change(function(){//code...}); //为 ...

  10. php 变量名前加一个下划线含义

    https://segmentfault.com/q/1010000006467833 一个下划线是私有变量以及私有方法两个下划线是PHP内置变量. 以下划线开头,表示为类的私有成员. 这只是个不成文 ...