1. 程式人生 > >Django框架原理

Django框架原理

tran onf isp live lencod ted url地址 mime ask

一、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\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 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8\r\n\r\n

按換行分隔後的請求部分

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\r\n
請求方式: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 協議版本\r\n
k1: v1\r\n
k2:v2\r\n
\r\n
請求體(請求數據) 可以有可以沒有 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)響應體

響應體是服務器回寫給客戶端的頁面正文,瀏覽器將正文加載到內存,然後解析渲染顯示頁面內容

技術分享圖片

小結:

格式:
“協議版本 狀態碼 狀態描述符\r\n
k1: v1\r\n
k2:v2\r\n
Content-Type:text/html;charset=utf-8\r\n
\r\n
響應體 (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\r\n\r\n)
    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\r\n\r\n‘)

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\r\n\r\n‘)

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\r\n\r\n‘)
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(‘@@time@@‘,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\r\n\r\n‘)
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>當前時間是:@@time@@</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(@@time@@, 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框架原理