web应用与web框架本质

概念

什么是web应用程序呢? Web应用程序就一种可以通过互联网来访问资源的应用程序, 用户可以只需要用一个浏览器而不需要安装其他程序就可以访问自己需要的资源.

应用软件通常有两种架构: B/S架构和传统的C/S架构. C/S架构是客户端/服务端程序, 用户需要访问服务器需要下载单独的客户端, 而B/S则是浏览器/服务端应用程序, 用户只需要选择兼容的合适的浏览器, 如IE, Chrome, Firefox等等来运行即可. Web应用程序通常就是属于B/S架构 ,这也是现在的主流软件架构.

Web应用程序是基于网络进行传输的, 而在网络上传输就需要通过socket, 一般都是通过TCP/IP协议来进行通信的, 因此我们可以这样理解Web应用, 浏览器就是Socket客户端程序, 而Web应用程序就是Socket服务端程序.

最简易socket服务端

有了这个认识, 客户端程序不需要我们负责, 我们就可以基于socket专心搭建一个服务端就可以完成简易版的Web应用了.

import socket

server = socket.socket()
server.bind(('localhost', 8080))
server.listen(5) while True:
# 开启接收客户端的程序
conn, addr = server.accept()
data = conn.recv(1024)
# 这里打印看来自服务端
print(data)
# 返回响应信息
response = 'Hello World!!!'
conn.send(response.encode('utf-8'))
conn.close() # 关闭连接

基于简单的socket, 我们接受了来自服务端的请求, 获得了如下的请求信息

b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36\r\nSec-Fetch-Mode: navigate\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nSec-Fetch-Site: cross-site\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=mUcuvpw1xeYvCqI0VUWuxOEDORAMVOZ1JHAkJXXEiajSi8KisZx6sTRke9H3AEyf\r\n\r\n'

我们返回了信息给浏览器, 浏览器的显示是

HTTP数据格式

这说明我们发送给浏览器的响应式无效的, Web应用程序想要在网络中完整的传输, 就一定需要遵从一定的通信协议,而在Web端这个应用层协议就是HTTP协议.

HTTP协议是有属于它自己的传输数据的格式的, HTTP的数据格式包含以下部分:

  • 请求首行 协议版本, 请求方式
  • 请求头 包含多个键值对形式的请求信息
  • \r\n
  • 请求体

服务端的响应格式也与之相对应:

  • 响应首行 协议版本, 状态码
  • 响应头 包含多个键值对形式的响应信息
  • \r\n
  • 响应体

返回正确响应

了解了HTTP的基本数据格式之后, 只要我们发送合法的响应信息, 就能和浏览器做一个基本的通信了, 然后继续修改上述的代码.

...
# 返回响应头
response = 'HTTP/1.1 200 OK\r\n\r\n'
# 返回响应体
response += '<h1>Hello World!!!</h1>'
...

只需要在响应加上响应首行和响应头信息, 并且我们可以在响应体中添加HTML标签, 这就可以让浏览器接收信息并正常解析出我们的响应信息了.

有了以上基础, 我们可以再修改代码, 让服务端返回一个html文件, 并在浏览器端正确渲染出来

...
# 返回响应头
response = 'HTTP/1.1 200 OK\r\n\r\n'
# 返回响应体
# response += '<h1>Hello World!!!</h1>'
with open('index.html', 'r', encoding='utf-8') as f:
response += f.read()
...
index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1 style="color: red">This is page index!</h1>
</body>
</html>

返回动态的页面

最后浏览器返回了上面的结果. 但是现在又有了新的需求, 这样每次都是返回固定的静态页面, 我们需要返回一个动态的页面. 这就希望页面不要被写死, 而需要动态的获取参数来渲染出响应的页面.就以下面这个动态获取当前的时间页面为例.

...
with open('time.html', 'r', encoding='utf-8') as f:
response += f.read()
response = response.replace('{{ now }}', time.strftime('%Y-%m-%d %X'))
conn.send(response.encode('utf-8'))
...
time.html
        
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>time</title>
</head>
<body>
<h1 style="color: red">This is time page!</h1>
<p>Now time is {{ now }} !</p>
</body>
</html>

最后的效果如下所示, 每次请求都显示不同的时间. 这里的思想也很容易, 就是用字符串的替换, 把特殊的字符换成我们最后需要

根据不同请求返回不同页面

现在达成了动态网页的需求, 我们的新需求又来了, 需要能根据用户敲入的不同网址返回不同的信息, 而这就需要我们对来自浏览器的请求进行分析, 请求首行包含了我们需要的请求地址的信息. 这就需要我们对来自浏览器的请求体进行字符串的切割处理了, 来获取我们需要的数据.

import socket
import time server = socket.socket()
server.bind(('localhost', 8080))
server.listen(5) def index():
with open('index.html', 'r', encoding='utf-8') as f:
return f.read() def get_time():
with open('time.html', 'r', encoding='utf-8') as f:
html = f.read()
return html.replace('{{ now }}', time.strftime('%Y-%m-%d %X')) while True:
# 开启接收客户端的程序
conn, addr = server.accept()
data = conn.recv(1024)
# 这里打印看来自服务端
print(data)
# 这里进行字符串的切割, 先以换行符来切割, 在以空格切割
path = data.decode('utf-8').split('\n')[0].split(' ')[1]
# print(path)
# 获取了路径之后, 我们就能够根据不同的请求路径返回不同的信息了.
response = 'HTTP/1.1 200 OK\r\n\r\n'
if path == '/index':
response += index()
elif path == '/time':
response += get_time()
else:
response += '404 error' conn.send(response.encode('utf-8'))
conn.close() # 关闭连接

我们的简易web服务端到了这已经有了点雏形了, 但是还不能支持并发, 并且我们还发现了前面的socket程序代码也是固定不变的, 处理浏览器请求头的过程是固定的, 返回的形式也是固定的, 而我们也只是简单的处理了请求路径的信息, 如果还需要其他信息, 就又要进行字符串的切割处理, 因此这样的处理工作是重复的, Python的原则是不要重复造轮子, 接下来就可以利用Python内置的wsgiref模块来完成前面这些固定的处理流程.

wsgi

wsgiref模块是一个遵从WSGI(web server gateway interface, web服务网关接口)协议, 那么什么是WSGI协议呢?在我们真实的生产环境中, 一般分为服务器程序和web应用程序.

  • 服务器程序 封装处理socket层面, 处理的是HTTP协议这一层的, 对请求的数据做处理, 然后交给应用程序处理
  • 应用程序则是负责具体的业务逻辑, 对来自浏览器的请求做业务逻辑层面的处理, 并返回相应的结果或页面返回.

在没有 WSGI 规范之前,一个服务器调度 Python 应用是用这种方式,另一款服务器使用的是那种方式,这样的话,编写出来的应用部署时只能选择局限的某个或某些服务器,达不到通用的效果。

所以,WSGI 的出现就是为了解决上面的问题,它规定了服务器怎么把请求信息告诉给应用,应用怎么把执行情况回传给服务器,这样的话,服务器与应用都按一个标准办事,只要实现了这个标准,服务器与应用随意搭配就可以,灵活度大大提高。

下面的图片说明了wsgi的工作流程.

首先浏览器发送请求到服务端, 服务端对数据进行处理, 并把请求信息封装到environ字典中, 并调用一个应用程序(这通常是一个可调用对象)来处理业务逻辑请求, 当应用程序处理完业务逻辑之后, 会调用start_response这个回调函数来发送状态信息, 响应头部的信息和可能出现的异常错误信息. 发送完这个数据响应信息之后, 最后再返回一个可迭代对象(可以是字符串, 字典, 列表...)的数据信息给服务器程序. 最后再返回给客户端.

基于wsgiref模块的web程序

了解了什么是wsgi协议之后, 我们接下来就可以利用wsgiref模块来修改上面的应用程序了.

import time
from wsgiref import simple_server # 视图部分, 具体的处理逻辑
def index():
with open('index.html', 'r', encoding='utf-8') as f:
return f.read() def get_time():
with open('time.html', 'r', encoding='utf-8') as f:
html = f.read()
return html.replace('{{ now }}', time.strftime('%Y-%m-%d %X')) def error():
"""请求路径不能匹配返回的信息"""
return '404 error' urls = [
('/index', index),
('/time', get_time)
] def run(environ, start_response):
"""
我们的app应用的入口函数
:param environ: 服务器处理过后的请求参数都包含在里面了, 包含请求路径信息等
:param start_response: 处理完数据后调用的响应回调函数
""" # 根据请求信息的不同, 来到不同的视图函数进行业务逻辑的处理
path = environ.get('PATH_INFO') # 包含了请求的路径信息
func = None
for url, f in urls:
if url == path:
func = f
break
# 如果url全部不匹配返回错误页面的信息
res = func() if func else error() # 数据处理完毕, 这里要调用响应的回调函数, 进行处理, 响应头信息
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])
# 最后返回可迭代数据信息
return [res.encode('utf-8'), ] if __name__ == '__main__':
# 创建一个服务器应用程序, 绑定ip端口和要调用的app入口函数
server = simple_server.make_server('localhost', 8080, run)
server.serve_forever() # 服务器永远启动着

上面的wsgiref模块实现的服务器严格的按照了wsgi协议, 我们自己实现的应用程序也遵守了wsgi接口规范, 这就让双方可以完美对接, 服务器程序和应用程序亦可以很大程度的实现解耦.

Django 简介

介绍

Django是一个由Python编写的具有完整架站能力的开源Web框架。使用Django,只要很少的代码,Python的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的Web服务。

Django本身基于MVC模型,即Model(模型)+View(视图)+ Controller(控制器)设计模式,因此天然具有MVC的出色基因:开发快捷、部署方便、可重用性高、维护成本低等。Python加Django是快速开发、设计、部署网站的最佳组合。

特点

Django具有以下特点:

  • 功能完善、要素齐全:该有的、可以没有的都有,常用的、不常用的工具都用。Django提供了大量的特性和工具,无须你自己定义、组合、增删及修改。但是,在有些人眼里这被认为是‘臃肿’不够灵活,发挥不了程序员的主动能力。
  • 完善的文档:经过十多年的发展和完善,Django有广泛的实践经验和完善的在线文档, 开发者遇到问题时可以搜索在线文档寻求解决方案。
  • 强大的数据库访问组件:Django的Model层自带数据库ORM组件,使得开发者无须学习其他数据库访问技术(SQL、pymysql、SQLALchemy等)。当然你也可以不用Django自带的ORM,而是使用其它访问技术,比如SQLALchemy。
  • 灵活的URL映射:Django使用正则表达式管理URL映射,灵活性高。
  • 丰富的Template模板语言:类似jinjia2模板语言,不但原生功能丰富,还可以自定义模板标签。
  • 自带免费的后台管理系统:只需要通过简单的几行配置和代码就可以实现一个完整的后台数据管理控制平台。
  • 完整的错误信息提示:在开发调试过程中如果出现运行错误或者异常,Django可以提供非常完整的错误信息帮助定位问题。

参考

  1. 参考1

  2. 参考2

django框架简介及自定义简易版框架的更多相关文章

  1. Layui框架+PHP打造个人简易版网盘系统

    网盘系统   大家应该都会注册过致命的一些网盘~如百度云.百科介绍:网盘,又称网络U盘.网络硬盘,是由互联网公司推出的在线存储服务,服务器机房为用户划分一定的磁盘空间,为用户免费或收费提供文件的存储. ...

  2. 手动搭建简易web框架与django框架简介

    目录 纯手写简易web框架 基于wsgiref模块 动静态网页 简单了解jinja2模块 框架请求流程 python主流web框架 django框架 简介 应用app 命令操作django pycha ...

  3. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  4. python主流框架简介和Django框架的使用

    目录 一.手撸简易web框架 二.动静态网页 1. 静态网页 2. 动态网页 三.jinja2模板语法 1. jinja2的作用 四.python主流web框架 1. django 3. tornad ...

  5. Django框架简介,wsgiref 与 jinja2 模块

    目录 框架简介 wsgiref模块 jinja2 模块 框架简介 Django是一个web开发框架,用来开发web应用,本质就是, web框架+socket服务端 MVC框架和MTV框架 MVC,全名 ...

  6. Django框架简介及模板Template,filter

    Django框架简介 MVC框架和MTV框架 MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View) ...

  7. 闭关修炼180天--手写持久层框架(mybatis简易版)

    闭关修炼180天--手写持久层框架(mybatis简易版) 抛砖引玉 首先先看一段传统的JDBC编码的代码实现: //传统的JDBC实现 public static void main(String[ ...

  8. C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    C#基于Mongo的官方驱动手撸一个简易版MongoDB-ORM框架 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongo ...

  9. wsgiref模块、web框架、django框架简介

    """web框架:将前端.数据库整合到一起的基于互联网传输的python代码 web框架也可以简单的理解为是软件开发架构里面的'服务端'""" ...

随机推荐

  1. xml 需要转义的字符

    XML实体中不允许出现"&","<",">"等特殊字符,否则XML语法检查时将出错,如果编写的XML文件必须包含这些字符 ...

  2. H5 + WebGL 实现的楼宇自控 3D 可视化监控

    前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...

  3. C++学习笔记3_类.和相关函数

    1. 类*在C++中,struct和class没有明显差别,不同C#,class一定要new(手动开辟内存)出来struct Hero{ char name[64]; int sex;}void pr ...

  4. 学习笔记23_AspMVC项目

    *创建AspMVC项目 (1)会自动创建App_Data文件夹,是用户不能访问和下载的.一般用户能访问那些文件夹,可以在IIS中配置. (2)App_Start文件夹,用于放置与程序有关的配置文件. ...

  5. 安装ubuntu16虚拟机,下载android源码,配置编译环境

    Android 源码编译步骤: 我考虑了一下,目前电脑装了SSD,8G内存,使用虚拟机编译源码应该够用. 首先下载虚拟机软件,由于最近一直在使用virtualbox,感觉蛮不错了,下载地址: http ...

  6. 爬虫之CrawlSpider简单案例之读书网

    项目名py文件下 class DsSpider(CrawlSpider): name = 'ds' allowed_domains = ['dushu.com'] start_urls = ['htt ...

  7. 基于华为物联网IOT的应用开发 ---界面管理开发

    在前面随笔<基于华为物联网IOT的应用开发 --- 基于.net 的SDK封装>介绍过IOT中应用侧SDK的封装,主要就是基于华为IOT的应用侧封装,以便在应用系统中进行调用.应用侧SDK ...

  8. OI 经典诗歌

    键盘行 学校机房夜送客,枫叶蒟蒻秋瑟瑟.主人下马客在船,代码欲写无键盘.夜不AC惨将别,别时茫茫屏幕亮. 忽闻楼上键盘声,主人忘归客不发.寻声暗问敲者谁,键盘声停欲语迟.上楼相近邀相见,添酒回灯重开宴 ...

  9. 基本数据类型(While循环,For循环,列表以及相关用法)

    正常在没有学习循环情况下,我们要输出同样的语句,需要重复打印.相当重要!!!! While循环 将输出放在一行 end=""默认是换行 print("Hello Worl ...

  10. re模块的基本使用

    目录 re模块 常用元字符 特殊构造 贪婪模式 非贪婪模式 re的常用函数 re模块补充 关于re模块必须知道的知识点 re模块 re模块 , 即正则表达式 , 本身是一种小型的.高度专业化的编程语言 ...