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、请求部分

浏览器====>服务器

原始的请求部分

bGET / 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(bHTTP/1.1 200 OK

)
    conn.send(bOK)
    # 关闭连接
    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框架原理的主要内容,如果未能解决你的问题,请参考以下文章

Django框架基本原理1

Django之Web框架原理

如何在 Django Summernote 中显示编程片段的代码块?

Django rest_framewok框架的基本组件

[TimLinux] Django 信号

Django简介