day60html
http協議:http://www.javashuo.com/article/p-pektrouc-n.html程序員
全部HTTP響應的第一行都是狀態行,依次是當前HTTP版本號,3位數字組成的狀態代碼,以及描述狀態的短語,彼此由空格分隔。web
狀態代碼的第一個數字表明當前響應的類型:瀏覽器
雖然 RFC 2616 中已經推薦了描述狀態的短語,例如"200 OK"(狀態碼 狀態碼描述),"404 Not Found",可是WEB開發者仍然可以自行決定採用何種短語,用以顯示本地化的狀態描述或者自定義信息。服務器
'GET / HTTP/1.1 請求行( 請求方法 協議版本) Host: 127.0.0.1:8001 請求頭部 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1' 無請求數據
HTTP請求格式。app
網頁請求,後臺迴應。框架
===================================================================socket
""" 不完善的web服務端示例 """ import socket # 生成socket實例對象 sk = socket.socket() # 綁定IP和端口 sk.bind(("127.0.0.1", 8001)) # 監聽 sk.listen() # 寫一個死循環,一直等待客戶端來連我 while 1: # 獲取與客戶端的鏈接 conn, _ = sk.accept() # 接收客戶端發來消息 data = conn.recv(8096) print(data) # HTTP響應格式 協議版本 狀態碼 狀態碼描述 回車符換行符 conn.send(b'http/1.1 200 ok\r\n\r\n') # 給客戶端回覆消息 conn.send(b'<h1>hello s10!</h1>') # 關閉 conn.close() sk.close()
# HTTP響應格式 協議版本 狀態碼 狀態碼描述 回車符換行符函數
conn.send(b'http/1.1 200 ok\r\n\r\n')網站
按HTTP響應格式發送數據。
效果:
========================================================================================
響應頭,請求頭
1 """ 2 不完善的web服務端示例 3 """ 4 5 import socket 6 7 # 生成socket實例對象 8 sk = socket.socket() 9 # 綁定IP和端口 10 sk.bind(("127.0.0.1", 8001)) 11 # 監聽 12 sk.listen() 13 14 # 寫一個死循環,一直等待客戶端來連我 15 while 1: 16 # 獲取與客戶端的鏈接 17 conn, _ = sk.accept() 18 # 接收客戶端發來消息 19 data = conn.recv(8096) 20 print(data) 21 # 給客戶端回覆消息 22 conn.send(b'http/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n') 23 # 想讓瀏覽器在頁面上顯示出來的內容都是響應正文 24 conn.send(b'<h1>hello s10!</h1>') 25 # 關閉 26 conn.close() 27 sk.close()
其中content-type:text/html; charset=utf-8在響應格式中屬於響應頭。
22行爲響應格式。
關於HTTP協議:
1. 瀏覽器往服務端發的叫 請求(request)
請求的消息格式:
請求方法 路徑 HTTP/1.1\r\n
k1:v1\r\n
k2:v2\r\n
\r\n
請求數據
2. 服務端往瀏覽器發的叫 響應(response)
響應的消息格式:
HTTP/1.1 狀態碼 狀態描述符\r\n
k1:v1\r\n
k2:v2\r\n
\r\n
響應正文 <-- html的內容
根據不一樣的路徑返回不一樣的內容web服務端示例
1 """ 2 完善的web服務端示例 3 根據不一樣的路徑返回不一樣的內容 4 """ 5 6 import socket 7 8 # 生成socket實例對象 9 sk = socket.socket() 10 # 綁定IP和端口 11 sk.bind(("127.0.0.1", 8000)) 12 # 監聽 13 sk.listen() 14 15 # 寫一個死循環,一直等待客戶端來連我 16 while 1: 17 # 獲取與客戶端的鏈接 18 conn, _ = sk.accept() 19 # 接收客戶端發來消息 20 data = conn.recv(8096) 21 # 把收到的數據轉成字符串類型 22 data_str = str(data, encoding="utf-8") # bytes("str", enconding="utf-8") 23 # print(data_str) 24 # 用\r\n去切割上面的字符串 25 l1 = data_str.split("\r\n") 26 # print(l1[0]) 27 # 按照空格切割上面的字符串 28 l2 = l1[0].split() #GET /xiaohei/ HTTP/1.1\r\n 將第一行根據空格分開 29 url = l2[1] #取url 取第一行第二個數據 30 # 給客戶端回覆消息 31 conn.send(b'http/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n') 32 # 想讓瀏覽器在頁面上顯示出來的內容都是響應正文 33 34 # 根據不一樣的url返回不一樣的內容 35 if url == "/yimi/": 36 response = b'<h1>hello yimi!</h1>' 37 elif url == "/xiaohei/": 38 response = b'<h1>hello xiaohei!</h1>' 39 else: 40 response = b'<h1>404! not found!</h1>' 41 conn.send(response) 42 # 關閉 43 conn.close() 44 sk.close()
根據不一樣路徑返回不一樣內容。
動態的網頁
不一樣時候訪問,內容不一樣。
1 """ 2 完善的web服務端示例 3 函數版根據不一樣的路徑返回不一樣的內容 4 進階函數版 不寫if判斷了,用url名字去找對應的函數名 5 返回html頁面 6 返回動態的html頁面 7 """ 8 9 import socket 10 11 # 生成socket實例對象 12 sk = socket.socket() 13 # 綁定IP和端口 14 sk.bind(("127.0.0.1", 8001)) 15 # 監聽 16 sk.listen() 17 18 # 定義一個處理/yimi/的函數 19 def yimi(url): 20 with open("yimi.html", "r", encoding="utf-8") as f:#字符串類型讀取 21 ret = f.read() 22 import time 23 # 獲得替換後的字符串 html中內容被時間戳替換 24 ret2 = ret.replace("@@xx@@", str(time.time())) 25 return bytes(ret2, encoding="utf-8") 26 27 28 # 定義一個處理/xiaohei/的函數 29 def xiaohei(url): 30 with open("xiaohei.html", "rb") as f:#二進制讀取 31 ret = f.read() 32 return ret 33 34 35 # 定義一個專門用來處理404的函數 36 def f404(url): 37 ret = "你訪問的這個{} 找不到".format(url) 38 return bytes(ret, encoding="utf-8") 39 40 41 url_func = [ 42 ("/yimi/", yimi), 43 ("/xiaohei/", xiaohei), 44 ] 45 46 47 # 寫一個死循環,一直等待客戶端來連我 48 while 1: 49 # 獲取與客戶端的鏈接 50 conn, _ = sk.accept() 51 # 接收客戶端發來消息 52 data = conn.recv(8096) 53 # 把收到的數據轉成字符串類型 54 data_str = str(data, encoding="utf-8") # bytes("str", enconding="utf-8") 55 # print(data_str) 56 # 用\r\n去切割上面的字符串 57 l1 = data_str.split("\r\n") 58 # print(l1[0]) 59 # 按照空格切割上面的字符串 60 l2 = l1[0].split() 61 url = l2[1] 62 # 給客戶端回覆消息 63 conn.send(b'http/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n') 64 # 想讓瀏覽器在頁面上顯示出來的內容都是響應正文 65 66 # 根據不一樣的url返回不一樣的內容 67 # 去url_func裏面找對應關係 68 for i in url_func: 69 if i[0] == url: 70 func = i[1] 71 break 72 # 找不到對應關係就默認執行f404函數 73 else: 74 func = f404 75 # 拿到函數的執行結果 76 response = func(url) 77 # 將函數返回的結果發送給瀏覽器 78 conn.send(response) 79 # 關閉鏈接 80 conn.close()
html文件
xiaohei.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>小黑</title> </head> <body> <h1>day60 Web框架本質都講了些啥啊</h1> <p>小黑啊</p> <p>啊,真的是黑啊!</p> </body> </html>
yimi.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>yimi</title> </head> <body> <h1>day60 web框架的本質</h1> <p>海燕</p> <p>在蒼茫的大海上,狂風捲積着烏雲,在烏雲和大海之間,海燕像黑色的閃電,在高傲的飛翔</p> <a href="http://www.luffycity.com">程序員的夢想,點我直達</a> <audio src="song.ogg" controls="controls"></audio> <!--其中爲被替換內容--> <p>@@xx@@</p> </body> </html>
@@XX@@被替換。
動態的網頁:
本質上都是字符串的替換
字符串替換髮生在什麼地方:
在服務端替換完再返回給瀏覽器!!!
總結一下: 1. web框架的本質: socket服務端 與 瀏覽器的通訊 2. socket服務端功能劃分: a. 負責與瀏覽器收發消息(socket通訊) --> wsgiref/uWsgi/gunicorn... b. 根據用戶訪問不一樣的路徑執行不一樣的函數 c. 從HTML讀取出內容,而且完成字符串的替換 --> jinja2(模板語言) 3. Python中 Web框架的分類: 1. 按上面三個功能劃分: 1. 框架自帶a,b,c --> Tornado 2. 框架自帶b和c,使用第三方的a --> Django 3. 框架自帶b,使用第三方的a和c --> Flask 2. 按另外一個維度來劃分: 1. Django --> 大而全(你作一個網站能用到的它都有) 2. 其餘 --> Flask 輕量級