Django框架原理
Posted mjc69213
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django框架原理相关的知识,希望对你有一定的参考价值。
一、HTTP协议
1、什么是HTTP协议
协议就是约束双方的一个准则HTTP,超文本传输协议(HyperText Transfer Protocol) 是互联网上应用最为广泛的一种网络协议 所有的WWW文件都必须遵守这个标准 设计HTTP最初的目的是为了提供一种发布和接收html页面的方法、约束请求与响应的规则。
2、HTTP的组成部分
(1)请求
(2)响应
请求和响应都是成对存在的。
3、请求的发送方式
- 通过浏览器的地址栏
- 通过html当中的form表单
- 通过a链接的href
- src属性
4、请求部分
浏览器====>服务器
原始的请求部分
b‘GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8 ‘
按换行分隔后的请求部分
GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8
(1)请求行
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;
GET / HTTP/1.1
请求方式:POST、GET 请求的资源:/Myxq/login.html?username=myxq&pwd=1234 协议版本: HTTP/1.0 发送请求,创建一次连接 获得一个web资源,连接断开 HTTP/1.1 发送请求,创建一次连接 获得多个web资源,保持连接
(2)请求头
请求头是客户端发送给服务器端的一些信息,使用键值对表示key:value
常见请求头`Referer`: 浏览器通知服务器,当前请求来自何处。 如果是直接访问 则不会有这个头。常用于:防盗链 `If-Modified-Since`: 浏览器通知服务器 本地缓存的最后变更时间。 `Cookie`:用于存放浏览器缓存的cookie信息。 `User-Agent`: 浏览器通知服务器 客户端浏览器与操作系统相关信息 `Connection`: 保持连接状态。Keep-Alive 连接中,close 已关闭 `Host`:请求的服务器主机名 `Content-Length`:请求体的长度 `Content-Type`:如果是POST请求,会有这个头, 默认值为`application/x-www-form-urlencoded`, 表示请求体内容使用url编码 `Accept`: 浏览器可支持的MIME类型。 文件类型的一种描述方式`text/html` , `html`文件 `text/css`, `css`文件`text/javascript`, `js`文件`image`,所有图片文件 `Accept-Encoding`: 浏览器通知服务器 浏览器支持的数据压缩格式。 如:GZIP压缩 `Accept-Language`: 浏览器通知服务器,浏览器支持的语言 自动的把客户端的信息发送给服务器
(3)请求体
当请求方式是post的时,请求体会有请求的参数,如果请求方式为get,那么请求参数不会出现在请求体中,会拼接在url地址后面。
小结:
格式:
请求方式 URL 协议版本
k1: v1
k2:v2
请求体(请求数据) 可以有可以没有 GET请求没有请求数据
5、响应部分
服务器=====>浏览器
点击view source之后显示如下图
(1)响应行
服务器响应给客户端浏览器的状态码,根据不同的状态码,可以看出此次请求的结果如何
Http协议状态码 `200` :请求成功 302 :请求重定向 304 :请求资源没有改变,访问本地缓存。 404 :请求资源不存在。 通常是用户路径编写错误, 也可能是服务器资源已删除。 500 :服务器内部错误。通常程序抛异常。 其它状态码 成功 200 OK 201 已创建 202 接收 203 非认证信息 204 无内容 205 重置内容 206 部分内容 重定向 300 多路选择 301 永久转移 302 暂时转移 303 参见其它 304 未修改(`Not Modified`) 305 使用代理 客户方错误 400 错误请求(`Bad Request`) 401 未认证 402 需要付费 403 禁止(`Forbidden`) 404 未找到(`Not Found`) 405 方法不允许 406 不接受 407 需要代理认证 408 请求超时 409 冲突 410 失败 411 需要长度 412 条件失败 413 请求实体太大 414 请求URI太长 415 不支持媒体类型 服务器错误 500 服务器内部错误 501 未实现(`Not Implemented`) 502 网关失败 504 网关超时
(2)响应头
服务器端将信息,以键值对的形式返回给客户端
常见响应头 `Location`: 指定响应的路径 需要与状态码302配合使用,完成跳转 `Content-Type`: 响应正文的类型(MIME类型) `Content-Disposition`: 通过浏览器以下载方式解析正文 `Set-Cookie`: 服务器向浏览器写入cookie `Content-Encoding`: 服务器使用的压缩格式 `Content-length`: 响应正文的长度 `Refresh`:定时刷新 `Server`: 服务器名称,默认值:`Apache-Coyote/1.1`。 可以通过conf/server.xml配置进行修改 `Last-Modified`: 服务器通知浏览器,文件的最后修改时间 自动的把服务器端的信息传给客户端
(3)响应体
响应体是服务器回写给客户端的页面正文,浏览器将正文加载到内存,然后解析渲染显示页面内容
小结:
格式:
“协议版本 状态码 状态描述符
k1: v1
k2:v2
Content-Type:text/html;charset=utf-8
响应体 (HTML代码)”
二、web框架的本质
WSGI(Web Server Gateway Interface)规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。
所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。
1、自定义一个web框架
最简单的
# 导入模块 import socket # 创建一个socket对象 sk = socket.socket() # 绑定IP和端口 sk.bind((‘127.0.0.1‘,8000)) # 监听 sk.listen() while True: # 等待连接 conn, addr = sk.accept() # 接收消息 data = conn.recv(8000) print(data) # 发送消息 conn.send(b‘HTTP/1.1 200 OK ‘) conn.send(b‘OK‘) # 关闭连接 conn.close()
2、根据不同的路径返回不同的内容
# 导入模块
import socket
# 创建一个socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind((‘127.0.0.1‘,8000))
# 监听
sk.listen()
while True:
# 等待连接
conn, addr = sk.accept()
# 接收消息
data = conn.recv(8000)
url = data.decode(‘utf-8‘).split()[1]
# 发送消息
conn.send(b‘HTTP/1.1 200 OK ‘)
if url == ‘/oumei/‘:
conn.send(b‘welcome to oumei bankuai‘)
elif url == ‘/rihan/‘:
conn.send(b‘welcome to rihan bankuai‘)
else:
conn.send(b‘luzhizhong‘)
# 关闭连接
conn.close()
3、根据不同的路径返回不同的内容--函数版
# 导入模块
import socket
# 创建一个socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind((‘127.0.0.1‘,8000))
# 监听
sk.listen()
def oumei(url):
return b‘welcome to oumei bankuai‘
def rihan(url):
return b‘welcome to rihan bankuai‘
while True:
# 等待连接
conn, addr = sk.accept()
# 接收消息
data = conn.recv(8000)
url = data.decode(‘utf-8‘).split()[1]
# 发送消息
conn.send(b‘HTTP/1.1 200 OK ‘)
if url == ‘/oumei/‘:
response = oumei(url)
elif url == ‘/rihan/‘:
response = rihan(url)
else:
response = b‘luzhizhong‘
# 返回信息
conn.send(response)
# 关闭连接
conn.close()
4、根据不同的路径返回不同的内容--函数进阶版
# 导入模块
import socket
# 创建一个socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind((‘127.0.0.1‘,8000))
# 监听
sk.listen()
def oumei(url):
return b‘welcome to oumei bankuai‘
def rihan(url):
return b‘welcome to rihan bankuai‘
def dongnanya(url):
return b‘welcome to dongnanya bankuai‘
# 定义一个URL和函数的对应函数
list1 = [
(‘/oumei/‘,oumei),
(‘/rihan/‘,rihan),
(‘/dongnanya/‘,dongnanya),
]
while True:
# 等待连接
conn, addr = sk.accept()
# 接收消息
data = conn.recv(8000)
url = data.decode(‘utf-8‘).split()[1]
# 发送消息
conn.send(b‘HTTP/1.1 200 OK ‘)
func = None
for i in list1:
if i[0] == url:
func = i[1]
break
if func:
response = func(url)
else:
response = b‘404 not found‘
# 返回信息
conn.send(response)
# 关闭连接
conn.close()
5、返回具体的HTML文件
服务端:
# 导入模块
import socket
# 创建一个socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind((‘127.0.0.1‘,8000))
# 监听
sk.listen()
def timer(url):
import time
with open(‘time.html‘,‘r‘,encoding=‘utf-8‘) as f:
ret = f.read()
ret = ret.replace(‘@@[email protected]@‘,time.strftime("%Y-%m-%d %H:%M:%S"))
return ret.encode(‘utf-8‘)
def index(url):
with open(‘index.html‘,‘rb‘) as f:
return f.read()
def oumei(url):
return b‘welcome to oumei bankuai‘
def rihan(url):
return b‘welcome to rihan bankuai‘
def dongnanya(url):
return b‘welcome to dongnanya bankuai‘
# 定义一个URL和函数的对应函数
list1 = [
(‘/oumei/‘,oumei),
(‘/rihan/‘,rihan),
(‘/dongnanya/‘,dongnanya),
(‘/index/‘,index),
(‘/time/‘,timer),
]
while True:
# 等待连接
conn, addr = sk.accept()
# 接收消息
data = conn.recv(8000)
url = data.decode(‘utf-8‘).split()[1]
# 发送消息
conn.send(b‘HTTP/1.1 200 OK ‘)
func = None
for i in list1:
if i[0] == url:
func = i[1]
break
if func:
response = func(url)
else:
response = b‘404 not found‘
# 返回信息
conn.send(response)
# 关闭连接
conn.close()
index网页页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>这是index页面</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>当前时间是:@@[email protected]@</h1>
</body>
</html>
6、wsgi版
from wsgiref.simple_server import make_server # 将返回不同的内容部分封装成函数 def index(url): # 读取index.html页面的内容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字节数据 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") def timer(url): import time with open("time.html", "r", encoding="utf8") as f: s = f.read() s = s.replace(‘@@[email protected]@‘, time.strftime("%Y-%m-%d %H:%M:%S")) return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ("/time/", timer), ] def run_server(environ, start_response): start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘), ]) # 设置HTTP响应的状态码和头信息 url = environ[‘PATH_INFO‘] # 取到用户输入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == ‘__main__‘: httpd = make_server(‘127.0.0.1‘, 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
7、jinja2渲染版
from wsgiref.simple_server import make_server from jinja2 import Template def index(url): # 读取HTML文件内容 with open("index2.html", "r", encoding="utf8") as f: data = f.read() template = Template(data) # 生成模板文件 ret = template.render({‘name‘: ‘egon‘, ‘hobby_list‘: [‘街舞‘, ‘喝酒‘, ‘烫头‘]}) # 把数据填充到模板中 return bytes(ret, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘), ]) # 设置HTTP响应的状态码和头信息 url = environ[‘PATH_INFO‘] # 取到用户输入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == ‘__main__‘: httpd = make_server(‘127.0.0.1‘, 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
小结:
web框架
本质: socket服务端
功能:
a. socket收发消息
b. URL和函数的对应关系,根据不同的URL执行不同的函数,返回函数的结果
c. 读取HTML文件,进行了一个字符替换(模板渲染)
分类:
Django flask tornado
完成了a,b,c三个功能的 ——》 tornado
完成了b,c 两个功能 ——》 Django
完成了b 一个功能 ——》 flask
另一种分类:
1. Django 大而全
2. 其他 短小精悍
以上是关于Django框架原理的主要内容,如果未能解决你的问题,请参考以下文章