Django之web框架的本质
生活随笔
收集整理的這篇文章主要介紹了
Django之web框架的本质
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
web框架的本質及自定義web框架
我們可以這樣理解:所有的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端,基于請求做出響應,客戶都先請求,服務端做出對應的響應,按照http協議的請求協議發送請求,服務端按照http協議的響應協議來響應請求,這樣的網絡通信,我們就可以自己實現Web框架了。
簡單的web框架
創建一個python文件,內容如下,名稱為test.py
(day53) import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() conn,addr = sk.accept() from_b_msg = conn.recv(1024) str_msg = from_b_msg.decode('utf-8') #socket是應用層和傳輸層之間的抽象層,每次都有協議,協議就是消息格式,那么傳輸層的消息格式我們不用管,因為socket幫我們搞定了,但是應用層的協議還是需要咱們自己遵守的,所以再給瀏覽器發送消息的時候,如果沒有按照應用層的消息格式來寫,那么你返回給瀏覽器的信息,瀏覽器是沒法識別的。而應用層的協議就是我們的HTTP協議,所以我們按照HTTP協議規定的消息格式來給瀏覽器返回消息就沒有問題了,關于HTTP我們會細說,首先看一下直接寫conn.send(b'hello')的效果,然后運行代碼,通過瀏覽器來訪問一下,然后再看這一句conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello')的效果 #下面這句就是按照http協議來寫的 # conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello') #上面這句還可以分成下面兩句來寫 conn.send(b'HTTP/1.1 200 ok \r\n\r\n') conn.send(b'hello')瀏覽器發送的請求:
目前還沒有寫如何返回一個HTML文件給瀏覽器,點開127.0.0.1看看:
在python文件中打印一下瀏覽器發過來的請求信息:
重新啟動代碼,在網址中輸入:
在重新啟動代碼,在網址中輸入:
http協議:工作原理
HTTP協議定義Web客戶端如何從Web服務器請求Web頁面,以及服務器如何把Web頁面傳送給客戶端。HTTP協議采用了請求/響應模型。客戶端向服務器發送一個請求報文,請求報文包含請求的方法、URL、協議版本、請求頭部和請求數據。服務器以一個狀態行作為響應,響應的內容包括協議的版本、成功或者錯誤代碼、服務器信息、響應頭部和響應數據。
以下是 HTTP 請求/響應的步驟:
\1. 客戶端連接到Web服務器
一個HTTP客戶端,通常是瀏覽器,與Web服務器的HTTP端口(默認為80)建立一個TCP套接字連接。例如,http://www.luffycity.com。
\2. 發送HTTP請求
通過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。
\3. 服務器接受請求并返回HTTP響應
Web服務器解析請求,定位請求資源。服務器將資源復本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。
\4. 釋放連接TCP連接
若connection 模式為close,則服務器主動關閉TCP連接,客戶端被動關閉連接,釋放TCP連接;若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;
\5. 客戶端瀏覽器解析HTML內容
客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然后解析每一個響應頭,響應頭告知以下為若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,并在瀏覽器窗口中顯示。
例如:在瀏覽器地址欄鍵入URL,按下回車之后會經歷以下流程:
瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;
解析出 IP 地址后,根據該 IP 地址和默認端口 80,和服務器建立TCP連接;
瀏覽器發出讀取文件(URL 中域名后面部分對應的文件)的HTTP 請求,該請求報文作為 TCP 三次握手的第三個報文的數據發送給服務器;
服務器對瀏覽器請求作出響應,并把對應的 html 文本發送給瀏覽器;
釋放 TCP連接;
瀏覽器將該 html 文本并顯示內容;
http協議特點
1.基于 請求(request)-響應(response) 的模式
HTTP協議規定,請求從客戶端發出,最后服務器端響應該請求并 返回。換句話說,肯定是先從客戶端開始建立通信的,服務器端在沒有 接收到請求之前不會發送響應 2.無狀態保存HTTP是一種不保存狀態,即無狀態(stateless)協議。HTTP協議 自身不對請求和響應之間的通信狀態進行保存。也就是說在HTTP這個 級別,協議對于發送過的請求或響應都不做持久化處理。使用HTTP協議,每當有新的請求發送時,就會有對應的新響應產 生。協議本身并不保留之前一切的請求或響應報文的信息。這是為了更快地處理大量事務,確保協議的可伸縮性,而特意把HTTP協議設計成 如此簡單的。可是,隨著Web的不斷發展,因無狀態而導致業務處理變得棘手 的情況增多了。比如,用戶登錄到一家購物網站,即使他跳轉到該站的 其他頁面后,也需要能繼續保持登錄狀態。針對這個實例,網站為了能 夠掌握是誰送出的請求,需要保存用戶的狀態。HTTP/1.1雖然是無狀態協議,但為了實現期望的保持狀態功能, 于是引入了Cookie技術。有了Cookie再用HTTP協議通信,就可以管 理狀態了。有關Cookie的詳細內容稍后講解。 3.無連接 無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,并收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間,并且可以提高并發性能,不能和每個用戶建立長久的連接,請求一次相應一次,服務端和客戶端就中斷了。但是無連接有兩種方式,早期的http協議是一個請求一個響應之后,直接就斷開了,但是現在的http協議1.1版本不是直接就斷開了,而是等幾秒鐘,這幾秒鐘是等什么呢,等著用戶有后續的操作,如果用戶在這幾秒鐘之內有新的請求,那么還是通過之前的連接通道來收發消息,如果過了這幾秒鐘用戶沒有發送新的請求,那么就會斷開連接,這樣可以提高效率,減少短時間內建立連接的次數,因為建立連接也是耗時的,默認的好像是3秒中現在,但是這個時間是可以通過咱們后端的代碼來調整的,自己網站根據自己網站用戶的行為來分析統計出一個最優的等待時間。http請求方法
請求方式:get 和 post
GET提交的數據會放在URL之后,也就是請求行里面,以?分割URL和傳輸數據,參數之間以&相連,如EditBook?name=test1&id=123456.(請求頭里面那個content-type做的這種參數形式,后面講) POST方法是把提交的數據放在HTTP包的請求數據部分中.
GET提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
GET與POST請求在服務端獲取請求數據方式不同,就是我們自己在服務端取請求數據的時候的方式不同了
常用的get請求方式:瀏覽器輸入網址 ,a標簽 ,form標簽 method='get'
post請求方法,一般都用來提交數據.比如用戶名密碼登錄
其他方法:
HEAD
與GET方法一樣,都是向服務器發出指定資源的請求。只不過服務器將不傳回資源的本文部分。它的好處在于,使用這個方法可以在不必傳輸全部內容的情況下,就可以獲取其中“關于該資源的信息”(元信息或稱元數據)。
PUT
向指定資源位置上傳其最新內容。
DELETE
請求服務器刪除Request-URI所標識的資源。
TRACE
回顯服務器收到的請求,主要用于測試或診斷。
OPTIONS
這個方法可使服務器傳回該資源所支持的所有HTTP請求方法。用'*'來代替資源名稱,向Web服務器發送OPTIONS請求,可以測試服務器功能是否正常運作。
CONNECT
這個方法可使服務器傳回該資源所支持的所有HTTP請求方法。用'*'來代替資源名稱,向Web服務器發送OPTIONS請求,可以測試服務器功能是否正常運作。
http響應狀態碼
1xx消息——請求已被服務器接收,繼續處理
2xx成功——請求已成功被服務器接收、理解、并接受 3xx重定向——需要后續操作才能完成這一請求 4xx請求錯誤——請求含有詞法錯誤或者無法被執行 5xx服務器錯誤——服務器在處理某個正確請求時發生錯誤URL
超文本傳輸協議(HTTP)的統一資源定位符將從因特網獲取信息的五個基本元素包括在一個簡單的地址中:
傳送協議。
層級URL標記符號(為[//],固定不變)
訪問資源需要的憑證信息(可省略)
服務器。(通常為域名,有時為IP地址)
端口號。(以數字方式表示,若為HTTP的默認值“:80”可省略)
路徑。(以“/”字符區別路徑中的每一個目錄名稱)
查詢。(GET模式的窗體參數,以“?”字符為起點,每個參數以“&”隔開,再以“=”分開參數名稱與數據,通常以UTF8的URL編碼,避開字符沖突的問題)
片段。以“#”字符為起點
以http://www.luffycity.com:80/news/index.html?id=250&page=1 為例, 其中:http,是協議;www.luffycity.com,是服務器;80,是服務器上的默認網絡端口號,默認不顯示;/news/index.html,是路徑(URI:直接定位到對應的資源);?id=250&page=1,是查詢。大多數網頁瀏覽器不要求用戶輸入網頁中“http://”的部分,因為絕大多數網頁內容是超文本傳輸協議文件。同樣,“80”是超文本傳輸協議文件的常用端口號,因此一般也不必寫明。一般來說用戶只要鍵入統一資源定位符的一部分(www.luffycity.com:80/news/index.html?id=250&page=1)就可以了。 由于超文本傳輸協議允許服務器將瀏覽器重定向到另一個網頁地址,因此許多服務器允許用戶省略網頁地址中的部分,比如 www。從技術上來說這樣省略后的網頁地址實際上是一個不同的網頁地址,瀏覽器本身無法決定這個新地址是否通,服務器必須完成重定向的任務。
http請求和相應格式格式
請求 和 響應請求格式GET / HTTP/1.1 --- GET /clschao/articles/9230431.html?name=chao&age=18 HTTP/1.1User-Agent:....xx:xx請求數據 get請求方法沒有請求數據 post請求數據方法的請求數據放在這里響應格式HTTP/1.1 200 okkl:v1k2:v2響應數據返回HTML文件的web框架
寫一個html文件,名稱為test.html:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="test.css"><!--加上下面這句,那么我們看瀏覽器調試窗口中的那個network里面就沒有那個favicon.ico的請求了,其實這就是頁面title標簽文字左邊的那個頁面圖標,但是這個文件是我們自己本地的,所以我們需要在后端代碼里面將這個文件數據讀取出來返回給前端--><link rel="icon" href="wechat.ico"><!--直接寫在html頁面里面的css樣式是直接可以在瀏覽器上顯示的--><!--<style>--><!--h1{--><!--background-color: green;--><!--color: white;--><!--}--><!--</style>--> </head> <body><h1>姑娘,你好,我是Jaden,請問約嗎?嘻嘻~~</h1> <!--直接寫在html頁面里面的img標簽的src屬性值如果是別人網站的地址(網絡地址)是直接可以在瀏覽器上顯示的--> <!--<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550395461724&di=c2b971db12eef5d85aba410d1e2e8568&imgtype=0&src=http%3A%2F%2Fy0.ifengimg.com%2Fifengimcp%2Fpic%2F20140822%2Fd69e0188b714ee789e97_size87_w800_h1227.jpg" alt="">--> <!--如果都是網絡地址,那么只要你的電腦有網,就可以看到,不需要自己在后端寫對應的讀取文件,返回圖片文件信息的代碼,因為別人的網站就做了這個事情了--> <img src="meinv.png" alt="" width="100" height="100"> <!--如果你是本地的圖片想要返回給頁面,你需要對頁面上的關于這個圖片的請求要自己做出響應,這個src就是來你本地請求這個圖片,你只要將圖片信息讀取出來,返回給頁面,頁面拿到這個圖片的數據,就能夠渲染出來了,是不是很簡單--><!--直接寫在html頁面里面的js操作是直接可以在瀏覽器上顯示的--> <!--<script>--><!--alert('這是我們第一個網頁')--> <!--</script>--><script src="test.js"></script> </body> </html>服務端程序,文件名稱為test.py:
import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() conn,addr = sk.accept() from_b_msg = conn.recv(1024) str_msg = from_b_msg.decode('utf-8') print('瀏覽器請求信息:',str_msg)# conn.send(b'HTTP/1.1 200 ok \r\ncontent-type:text/html;charset=utf-8;\r\n') conn.send(b'HTTP/1.1 200 ok \r\n\r\n')with open('test1.html','rb') as f:f_data = f.read() conn.send(f_data)返回靜態文件的高級web框架
還是使用第一個web框架的html文件,只需要寫一些服務端程序:
import socketsk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen()#首先瀏覽器相當于給我們發送了多個請求,一個是請求我們的html文件,而我們的html文件里面的引入文件的標簽又給我們這個網站發送了請求靜態文件的請求,所以我們要將建立連接的過程循環起來,才能接受多個請求,沒毛病 while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')#通過http協議我們知道,瀏覽器請求的時候,有一個請求內容的路徑,通過對請求信息的分析,這個路徑我們在請求的所有請求信息中可以提煉出來,下面的path就是我們提煉出來的路徑path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')#由于整個頁面需要html、css、js、圖片等一系列的文件,所以我們都需要給人家瀏覽器發送過去,瀏覽器才能有這些文件,才能很好的渲染你的頁面#根據不同的路徑來返回響應的內容if path == '/': #返回html文件print(from_b_msg)with open('test.html','rb') as f:# with open('Python開發.html','rb') as f:data = f.read()conn.send(data)conn.close()elif path == '/meinv.png': #返回圖片with open('meinv.png','rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()elif path == '/test.css': #返回css文件with open('test.css','rb') as f:css_data = f.read()conn.send(css_data)conn.close()elif path == '/wechat.ico':#返回頁面的ico圖標with open('wechat.ico','rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()elif path == '/test.js': #返回js文件with open('test.js','rb') as f:js_data = f.read()conn.send(js_data)conn.close()#注意:上面每一個請求處理完之后,都有一個conn.close()是因為,HTTP協議是短鏈接的,一次請求對應一次響應,這個請求就結束了,所以我們需要寫上close,不然瀏覽器自己斷了,你自己寫的服務端沒有斷,就會出問題。函數版高級web框架
還是使用第一個web框架的html文件,只需要寫一些服務端程序:
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2019/2/17 14:06 # @Author : wuchao # @Site : # @File : test.py # @Software: PyCharm import socketsk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen()#處理頁面請求的函數 def func1(conn):with open('test.html', 'rb') as f:# with open('Python開發.html','rb') as f:data = f.read()conn.send(data)conn.close()#處理頁面img標簽src屬性值是本地路徑的時候的請求 def func2(conn):with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close() #處理頁面link( <link rel="stylesheet" href="test.css">)標簽href屬性值是本地路徑的時候的請求 def func3(conn):with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()#處理頁面link(<link rel="icon" href="wechat.ico">)標簽href屬性值是本地路徑的時候的請求 def func4(conn):with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()#處理頁面script(<script src="test.js"></script>)標簽src屬性值是本地路徑的時候的請求 def func5(conn):with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':func1(conn)elif path == '/meinv.png':func2(conn)elif path == '/test.css':func3(conn)elif path == '/wechat.ico':func4(conn)elif path == '/test.js':func5(conn)更高級(多線程版)web框架
應用上并發編程內容html文件和靜態文件都直接給瀏覽器,html文件和靜態文件還是上面的
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2019/2/17 14:06 # @Author : wuchao # @Site : # @File : test.py # @Software: PyCharm import socket from threading import Thread #注意一點,不開多線程完全是可以搞定的,在這里只是教大家要有并發編程的思想,所以我使用了多線程sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen()def func1(conn):with open('test.html', 'rb') as f:# with open('Python開發.html','rb') as f:data = f.read()conn.send(data)conn.close()def func2(conn):with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()def func3(conn):with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()def func4(conn):with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()def func5(conn):with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':# func1(conn)t = Thread(target=func1,args=(conn,))t.start()elif path == '/meinv.png':# func2(conn)t = Thread(target=func2, args=(conn,))t.start()elif path == '/test.css':# func3(conn)t = Thread(target=func3, args=(conn,))t.start()elif path == '/wechat.ico':# func4(conn)t = Thread(target=func4, args=(conn,))t.start()elif path == '/test.js':# func5(conn)t = Thread(target=func5, args=(conn,))t.start()更更高級版web框架
if判斷太多,開線程方式也比較麻煩有多少個if判斷,就寫多少次創建線程,簡化一下:
import socket from threading import Threadsk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen()def func1(conn):conn.send(b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n')with open('test.html', 'rb') as f:# with open('Python開發.html','rb') as f:data = f.read()conn.send(data)conn.close()def func2(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()def func3(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()def func4(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()def func5(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()#定義一個路徑和執行函數的對應關系,不再寫一堆的if判斷了 l1 = [('/',func1),('/meinv.png',func2),('/test.css',func3),('/wechat.ico',func4),('/test.js',func5), ]#遍歷路徑和函數的對應關系列表,并開多線程高效的去執行路徑對應的函數, def fun(path,conn):for i in l1:if i[0] == path:t = Thread(target=i[1],args=(conn,))t.start()# else:# conn.send(b'sorry')while 1:conn,addr = sk.accept()#看完這里面的代碼之后,你就可以思考一個問題了,很多人要同時訪問你的網站,你在請求這里是不是可以開起并發編程的思想了,多進程+多線程+協程,妥妥的支持高并發,再配合服務器集群,這個網頁就支持大量的高并發了,有沒有很激動,哈哈,但是咱們寫的太low了,而且功能很差,容錯能力也很差,當然了,如果你有能力,你現在完全可以自己寫web框架了,寫一個nb的,如果現在沒有這個能力,那么我們就來好好學學別人寫好的框架把,首先第一個就是咱們的django框架了,其實就是將這些功能封裝起來,并且容錯能力強,抗壓能力強,總之一個字:吊。# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)# 注意:因為開啟的線程很快,可能導致你的文件還沒有發送過去,其他文件的請求已經來了,導致你文件信息沒有被瀏覽器正確的認識,所以需要將發送請求行和請求頭的部分寫道前面的每一個函數里面去,并且防止出現瀏覽器可能不能識別你的html文件的情況,需要在發送html文件的那個函數里面的發送請求行和請求頭的部分加上兩個請求頭content-type:text/html\r\ncharset:utf-8\r\n# conn.send(b'HTTP/1.1 200 ok\r\n\r\n') 不這樣寫了# conn.send(b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n') 不這樣寫了print(from_b_msg)#執行這個fun函數并將路徑和conn管道都作為參數傳給他fun(path,conn)根據不同路徑返回不同頁面的web框架
創建兩個html文件,寫幾個標簽在里面,名為index.html和home.html,然后根據不同的路徑返回不同的頁面,頁面不創建了,寫一下python代碼
""" 根據URL中不同的路徑返回不同的內容 返回獨立的HTML頁面 """import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽# 將返回不同的內容部分封裝成函數 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")# 定義一個url和實際要執行的函數的對應關系 list1 = [("/index/", index),("/home/", home), ]while 1:# 等待連接conn, add = sk.accept()data = conn.recv(8096) # 接收客戶端發來的消息# 從data中取到路徑data = str(data, encoding="utf8") # 把收到的字節類型的數據轉換成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1] # url是我們從瀏覽器發過來的消息中分離出的訪問路徑conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 因為要遵循HTTP協議,所以回復的消息也要加狀態行# 根據不同的路徑返回不同內容func = None # 定義一個保存將要執行的函數名的變量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具體的響應消息conn.send(response)conn.close()返回動態頁面的web框架
頁面顯示出來了但是都是靜態的。頁面內容都不會變化,我想要的是動態網站,動態網站的意思是里面有動態變化的數據,而不是頁面里面有動態效果。還是寫一下python代碼
""" 根據URL中不同的路徑返回不同的內容 返回HTML頁面 讓網頁動態起來 """import socket import timesk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽# 將返回不同的內容部分封裝成函數 def index(url):with open("index.html", "r", encoding="utf8") as f:s = f.read()now = str(time.time())s = s.replace("@@oo@@", now) # 在網頁中定義好特殊符號,用動態的數據去替換提前定義好的特殊符號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")# 定義一個url和實際要執行的函數的對應關系 list1 = [("/index/", index),("/home/", home), ]while 1:# 等待連接conn, add = sk.accept()data = conn.recv(8096) # 接收客戶端發來的消息# 從data中取到路徑data = str(data, encoding="utf8") # 把收到的字節類型的數據轉換成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1] # url是我們從瀏覽器發過來的消息中分離出的訪問路徑conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 因為要遵循HTTP協議,所以回復的消息也要加狀態行# 根據不同的路徑返回不同內容func = None # 定義一個保存將要執行的函數名的變量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具體的響應消息conn.send(response)conn.close()別人寫好的模塊搞得web框架,這個模塊是wsgiref:
wsgiref模塊版web框架
wsgiref怎么使用:
from wsgiref.simple_server import make_server # wsgiref本身就是個web框架,提供了一些固定的功能(請求和響應信息的封裝,不需要我們自己寫原生的socket了也不需要咱們自己來完成請求信息的提取了,提取起來很方便) #函數名字隨便起 def application(environ, start_response):''':param environ: 是全部加工好的請求信息,加工成了一個字典,通過字典取值的方式就能拿到很多你想要拿到的信息:param start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數:return:'''start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')])print(environ)print(environ['PATH_INFO']) #輸入地址127.0.0.1:8000,這個打印的是'/',輸入的是127.0.0.1:8000/index,打印結果是'/index'return [b'<h1>Hello, web!</h1>']#和咱們學的socketserver那個模塊很像啊 httpd = make_server('127.0.0.1', 8080, application)print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()模版渲染jinja2
下載方式
pip install jinja2需要一個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</title> </head> <body><h1>姓名:{{name}}</h1><h1>愛好:</h1><ul>{% for hobby in hobby_list %}<li>{{hobby}}</li>{% endfor %}</ul> </body> </html>使用jinja2渲染的html2文件
from wsgiref.simple_server import make_server from jinja2 import Templatedef index():with open("index2.html", "r",encoding='utf-8') as f:data = f.read()template = Template(data) # 生成模板文件ret = template.render({"name": "于謙", "hobby_list": ["燙頭", "泡吧"]}) # 把數據填充到模板里面return [bytes(ret, encoding="utf8"), ]# 定義一個url和函數的對應關系 URL_LIST = [("/index/", index), ]def run_server(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息url = environ['PATH_INFO'] # 取到用戶輸入的urlfunc = None # 將要執行的函數for i in URL_LIST:if i[0] == url:func = i[1] # 去之前定義好的url列表里找url應該執行的函數breakif func: # 如果能找到要執行的函數return func() # 返回函數的執行結果else:return [bytes("404沒有該頁面", encoding="utf8"), ]if __name__ == '__main__':httpd = make_server('', 8000, run_server)print("Serving HTTP on port 8000...")httpd.serve_forever()從數據庫查詢數據填充頁面
使用pymysql連接數據庫
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select name, age, department_id from userinfo") user_list = cursor.fetchall() cursor.close() conn.close()測試user表
CREATE TABLE user(id int auto_increment PRIMARY KEY,name CHAR(10) NOT NULL,hobby CHAR(20) NOT NULL )engine=innodb DEFAULT charset=UTF8;MVC和MTV框架
M:model.py 就是和數據庫打交道用的,創建表等操作
V:View 視圖(視圖函數,html文件)
C:controller 控制器(其實就是我百度云代碼里面那個urls文件里面的內容,url(路徑)分發與視圖函數的邏輯處理)
Django叫做MTV框架
M:model.py 就是和數據庫打交道用的,創建表等操作(和上面一樣)
T:templates 存放HTML文件的
V:View 視圖函數(邏輯處理)
轉載于:https://www.cnblogs.com/shuai-jie/p/11227004.html
總結
以上是生活随笔為你收集整理的Django之web框架的本质的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HashSet源码分析:JDK源码系列
- 下一篇: mac中apache服务器及虚拟主机配置