日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

Web 框架的本質及自定義 Web 框架

我們可以這樣理解:所有的 Web 應用本質上就是一個 socket 服務端,而用戶的瀏覽器就是一個 socket 客戶端,基于請求做出響應。客戶都先請求,服務端做出對應的響應,按照 HTTP 協議的請求協議發送請求,服務端按照 HTTP 協議的響應協議來響應請求。依據這樣的原理進行網絡通信,我們就可以實現自己的 Web 框架了。

通過對 socket 的學習,我們已經知道如何網絡通信,我們完全可以自己寫了。因為 socket 就是做網絡通信用的。下面我們就基于 socket 來自己實現一個 Web 框架。寫一個 Web 服務端,讓瀏覽器來請求,并通過自己的服務端把頁面返回給瀏覽器,瀏覽器渲染出我們想要的效果。在后面的學習中,大家提前準備一些文件:

html 文件內容如下,名稱為 test.html:

charset="UTF-8"> Title css"> 姑娘,你好,我是Jaden,請問約嗎?嘻嘻~~

css 文件內容如下,名稱為 test.css:

h1{ background-color: green; color: white; }

js 文件內容如下,名稱為 test.js :

alert('這是我們第一個網頁');

再準備一個圖片,名稱為 meinv.jpg,再準備一個 ico 文件,名稱為 wechat.ico,其實就是個圖片文件,微信官網打開之后,在瀏覽器最上面能夠看到


 

,把它保存下來

上面的文件都準備好之后,你用 PyCharm 新建一個項目,把文件都放到一個文件夾里面去,留著備用,像下面這個樣子:


 

然后開始寫我們的 Web 框架,我們分這么幾步來寫:

一、簡單的 Web 框架

創建一個 Python/ target=_blank class=infotextkey>Python 文件,內容如下,名稱為 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') #socket是應用層和傳輸層之間的抽象層,每次都有協議,協議就是消息格式,那么傳輸層的消息格式我們不用管,因為socket幫我們搞定了,但是應用層的協議還是需要咱們自己遵守的,所以再給瀏覽器發送消息的時候,如果沒有按照應用層的消息格式來寫,那么你返回給瀏覽器的信息,瀏覽器是沒法識別的。而應用層的協議就是我們的HTTP協議,所以我們按照HTTP協議規定的消息格式來給瀏覽器返回消息就沒有問題了,關于HTTP我們會細說,首先看一下直接寫conn.send(b'hello')的效果,然后運行代碼,通過瀏覽器來訪問一下,然后再看這一句conn.send(b'HTTP/1.1 200 ok rnrnhello')的效果 #下面這句就是按照http協議來寫的 # conn.send(b'HTTP/1.1 200 ok rnrnhello') #上面這句還可以分成下面兩句來寫 conn.send(b'HTTP/1.1 200 ok rnrn') conn.send(b'hello')

我們來瀏覽器上看一下瀏覽器發送的請求:


 

目前我們還沒有寫如何返回一個 HTML 文件給瀏覽器,所以這里暫時不用管它。那么我們點開這個 127.0.0.1 看看:


 

我們在 Python 文件中打印一下瀏覽器發送過來的請求信息是啥:


 

重啟我們的代碼,然后在網址中輸入這個:


 

再重啟我們的代碼,然后在網址中輸入這個:


 

瀏覽器發過來一堆的消息,我們給瀏覽器回復(響應)信息的時候,也要按照一個消息格式來寫,這些都是 HTTP 協議規定的。要了解 HTTP 協議的更多內容,可以參考 HTTP 協議。

二、返回 HTML 文件的 Web 框架

我們剛剛寫過一個名稱為 test.html 的 HTML 文件,先把 CSS、JS 和圖片相關的注釋取消掉,讓它們可以直接顯示:

Title 姑娘,你好,我是Jaden,請問約嗎?嘻嘻~~

準備我們的 Python 代碼,服務端程序,文件內容如下,文件名稱為 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 rncontent-type:text/html;charset=utf-8;rn') conn.send(b'HTTP/1.1 200 ok rnrn') with open('test1.html','rb') as f: f_data = f.read() # 將HTML頁面返回 conn.send(f_data)

頁面上輸入網址看效果,css 和 js 代碼的效果也有,very good:


 

但是我們知道,我們的 css 和 js 基本都是寫在本地的文件里面的啊,而且我們的圖片基本也是我們自己本地的啊。怎么辦?我們將上面我們提前準備好的 js 和 css 還有那個 .ico 結尾的圖片文件都準備好,來我們在來一個升級版的 Web 框架。其實 css、js、圖片等文件都叫做網站的靜態文件。

首先我們先看一個效果,如果我們直接將我們寫好的 css 和 js 還有 .ico 和圖片文件插入到我們的 HTML 頁面里面,就是下面這個 HTML 文件。

名稱為 test.html,內容如下:

Title 姑娘,你好,我是Jaden,請問約嗎?嘻嘻~~

同樣使用我們之前的 Python 程序,來看效果:


 

發現 js 和 css 的效果都沒有出來,并且我們看一下瀏覽器調試窗口的那個.NETwork:


 

在下來我們在 network 里面點擊那個 test.css 文件,看看請求是什么:


 

還有就是當我們直接在瀏覽器上保存某個頁面的時候,隨便一個頁面,我們到頁面上點擊右鍵另存為,然后存到本地的一個目錄下,你會發現這個頁面的 html、css、js、圖片等文件都跟著保存下來了,我保存了一下博客園首頁的頁面,看,是一個文件夾和一個 HTML 文件:


 

發現 js、css 還有圖片什么的都被保存了下來。這說明什么?說明這些文件本身就存在瀏覽器上了。哦,原來就是將 HTML 頁面需要的 css、js、圖片等文件也發送給瀏覽器就可以了。并且這些靜態文件都是瀏覽器單獨過來請求的,其實和標簽的屬性有有關系。css 文件是 link 標簽的 href 屬性:,js 文件是 script 標簽的 src 屬性:,圖片文件是 img 標簽的 src 屬性: ,那個 .ico 文件是 link 標簽的屬性:。其實這些屬性都會在頁面加載的時候,單獨到自己對應的屬性值里面取請求對應的文件數據。而且我們如果在值里面寫的都是自己本地的路徑,那么都會來自己的本地路徑來找。如果我們寫的是相對路徑,就會到我們自己的網址 + 文件名稱,這個路徑來找它需要的文件。所以我們只需要將這些請求做一些響應,將對應的文件數據相應給瀏覽器就可以了!

并且我們通過前面的查看,能夠發現,瀏覽器 url 的請求路徑我們知道是什么,靜態文件不是也這樣請求的嗎,好,我們針對不同的路徑給它返回不同的文件,

三、返回靜態文件的高級 Web 框架

還是用第二個 Web 框架里面的那個 HTML 文件,我們只需要寫一些我們的服務端程序就可以了。同樣是 test.py 文件,內容如下:

import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() #首先瀏覽器相當于給我們發送了多個請求,一個是請求我們的html文件,而我們的html文件里面的引入文件的標簽又給我們這個網站發送了請求靜態文件的請求,所以我們要將建立連接的過程循環起來,才能接受多個請求,沒毛病 while 1: conn,addr = sk.accept() from_b_msg = conn.recv(1024) str_msg = from_b_msg.decode('utf-8') #通過http協議我們知道,瀏覽器請求的時候,有一個請求內容的路徑,通過對請求信息的分析,這個路徑我們在請求的所有請求信息中可以提煉出來,下面的path就是我們提煉出來的路徑 path = str_msg.split('rn')[0].split(' ')[1] print('path>>>',path) conn.send(b'HTTP/1.1 200 ok rnrn') #由于整個頁面需要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 rnrn') 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,不然瀏覽器自己斷了,你自己寫的服務端沒有斷,就會出問題。

運行起來我們的 py 文件,然后在瀏覽器訪問一下我們的服務端,看效果:


 

666666,完全搞定了。自己通過 socket 已經完全搞定了 web 項目,激動不。哈哈,我們再來完善一下。

四、函數版高級 Web 框架

HTML 文件和其他的靜態文件還是我們上面使用的,我們這次只是用函數把方法封裝一下。

Python 代碼如下:

import socket 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() #處理頁面img標簽src屬性值是本地路徑的時候的請求 def func2(conn): with open('meinv.png', 'rb') as f: pic_data = f.read() # conn.send(b'HTTP/1.1 200 ok rnrn') conn.send(pic_data) conn.close() #處理頁面link( )標簽href屬性值是本地路徑的時候的請求 def func3(conn): with open('test.css', 'rb') as f: css_data = f.read() conn.send(css_data) conn.close() #處理頁面link()標簽href屬性值是本地路徑的時候的請求 def func4(conn): with open('wechat.ico', 'rb') as f: ico_data = f.read() conn.send(ico_data) conn.close() #處理頁面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('rn')[0].split(' ')[1] print('path>>>',path) conn.send(b'HTTP/1.1 200 ok rnrn') 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 文件和靜態文件還是上面的。

Python 代碼如下:

import socket from threading import Thread # 注意一點,因為HTTP是無連接的,一次請求完成即斷開連接。 # 所以即便有打開多個頁面,只要不恰好同時發出請求,不開多線程完全是可以搞定的。 # 在這里只是教大家要有并發編程的思想,所以我使用了多線程 sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() def func1(conn): with open('test.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 rnrn') 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('rn')[0].split(' ')[1] print('path>>>',path) conn.send(b'HTTP/1.1 200 ok rnrn') 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 Thread sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() def func1(conn): conn.send(b'HTTP/1.1 200 okrncontent-type:text/htmlrncharset:utf-8rnrn') 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 okrnrn') with open('meinv.png', 'rb') as f: pic_data = f.read() # conn.send(b'HTTP/1.1 200 ok rnrn') conn.send(pic_data) conn.close() def func3(conn): conn.send(b'HTTP/1.1 200 okrnrn') 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 okrnrn') 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 okrnrn') 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框架了,其實就是將這些功能封裝起來,并且容錯能力強,抗壓能力強,總之一個字:吊。 from_b_msg = conn.recv(1024) str_msg = from_b_msg.decode('utf-8') path = str_msg.split('rn')[0].split(' ')[1] print('path>>>',path) # 注意:因為開啟的線程很快,可能導致你的文件還沒有發送過去,其他文件的請求已經來了,導致你文件信息沒有被瀏覽器正確的認識,所以需要將發送請求行和請求頭的部分寫道前面的每一個函數里面去,并且防止出現瀏覽器可能不能識別你的html文件的情況,需要在發送html文件的那個函數里面的發送請求行和請求頭的部分加上兩個請求頭content-type:text/htmlrncharset:utf-8rn # conn.send(b'HTTP/1.1 200 okrnrn') 不這樣寫了 # conn.send(b'HTTP/1.1 200 okrncontent-type:text/htmlrncharset:utf-8rnrn') 不這樣寫了 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") # 把收到的字節類型的數據轉換成字符串 # 按rn分割 data1 = data.split("rn")[0] url = data1.split()[1] # url是我們從瀏覽器發過來的消息中分離出的訪問路徑 conn.send(b'HTTP/1.1 200 OKrnrn') # 因為要遵循HTTP協議,所以回復的消息也要加狀態行 # 根據不同的路徑返回不同內容 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()八、返回動態頁面的 Web 框架

這網頁能夠顯示出來了,但是都是靜態的啊。頁面的內容都不會變化的,我想要的是動態網站,動態網站的意思是里面有動態變化的數據,而不是頁面里面有動態效果,這個大家要注意啊。

沒問題,我也有辦法解決。我選擇使用字符串替換來實現這個需求。(這里使用時間戳來模擬動態的數據,還是只給大家 Python 代碼吧)

""" 根據URL中不同的路徑返回不同的內容 返回HTML頁面 讓網頁動態起來 """ import socket import time sk = 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("", 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") # 把收到的字節類型的數據轉換成字符串 # 按rn分割 data1 = data.split("rn")[0] url = data1.split()[1] # url是我們從瀏覽器發過來的消息中分離出的訪問路徑 conn.send(b'HTTP/1.1 200 OKrnrn') # 因為要遵循HTTP協議,所以回復的消息也要加狀態行 # 根據不同的路徑返回不同內容 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()

這八個框架讓大家滿意了吧,這下子明白整個 Web 框架的原理了吧,哈哈。但是我們寫的框架還是太 low 了,不夠強壯。那別人已經開發好了很多 nb 的框架了,如:Django、Flask、Tornado 等等,我們學學怎么用就可以啦。但是注意一個問題,我們在里面獲取路徑的時候,是按照 rn 來分割然后再通過空格來分割獲取到的路徑。但是如果不是 HTTP 協議的話,你自己要注意消息格式了。

接下來我們看一個別人寫好的模塊來搞的 Web 框架,這個模塊叫做 wsgiref。

九、wsgiref 模塊版 Web 框架

wsgiref 模塊其實就是將整個請求信息給封裝了起來,不需要你自己處理了。假如它將所有請求信息封裝成了一個叫做 request 的對象,那么你直接 request.path 就能獲取到用戶這次請求的路徑,request.method 就能獲取到本次用戶請求的請求方式(get 還是 post)等。那這個模塊用起來,我們再寫 Web 框架是不是就簡單了好多啊。

對于真實開發中的 Python Web 程序來說,一般會分為兩部分:服務器程序和應用程序。

服務器程序負責對 socket 服務器進行封裝,并在請求到來時,對請求的各種數據進行整理。

應用程序則負責具體的邏輯處理。為了方便應用程序的開發,就出現了眾多的 Web 框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。

這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對于服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。最簡單的 Web 應用就是先把 HTML 用文件保存好,用一個現成的 HTTP 服務器軟件,接收用戶請求,從文件中讀取 HTML,返回。如果要動態生成 HTML,就需要把上述步驟自己來實現。不過,接受 HTTP 請求、解析 HTTP 請求、發送 HTTP 響應都是苦力活,如果我們自己來寫這些底層代碼,還沒開始寫動態 HTML 呢,就得花個把月去讀 HTTP 規范。

正確的做法是底層代碼由專門的服務器軟件實現,我們用 Python 專注于生成 HTML 文檔。因為我們不希望接觸到 TCP 連接、HTTP 原始請求和響應格式。所以,需要一個統一的接口協議來實現這樣的服務器軟件,讓我們專心用 Python 編寫 Web 業務。

這時候,標準化就變得尤為重要。我們可以設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那么他們就可以配合使用。一旦標準確定,雙方各自實現。這樣,服務器可以支持更多支持標準的框架,框架也可以使用更多支持標準的服務器。

WSGI(Web Server Gateway Interface)就是一種規范,它定義了使用 Python 編寫的 Web 應用程序與 Web 服務器程序之間的接口格式,實現 Web 應用程序與 Web 服務器程序間的解耦。

常用的 WSGI 服務器有 uwsgi、Gunicorn。而 Python 標準庫提供的獨立 WSGI 服務器叫 wsgiref。Django 開發環境用的就是這個模塊來做服務器。

好,接下來我們就看一下(能理解就行,了解就可以了):先看看 wsfiref 怎么使用:

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', [('k1','v1'),]) print(environ) print(environ['PATH_INFO']) #輸入地址127.0.0.1:8000,這個打印的是'/',輸入的是127.0.0.1:8000/index,打印結果是'/index' return [b'Hello, web!'] #和咱們學的socketserver那個模塊很像啊 httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()

來一個完整的 Web 項目,用戶登錄認證的項目。我們需要連接數據庫了,所以先到 MySQL 數據庫里面準備一些表和數據:

mysql> create database db1; Query OK, 1 row affected (0.00 sec) mysql> use db1; Database changed mysql> create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null); Query OK, 0 rows affected (0.23 sec) mysql> insert into userinfo(username,password) values('chao','666'),('sb1','222'); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from userinfo; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | chao | 666 | | 2 | sb1 | 222 | +----+----------+----------+ 2 rows in set (0.00 sec)

然后再創建這么幾個文件:

Python 文件名稱 webmodel.py,內容如下:

#創建表,插入數據 def createtable(): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='666', database='db1', charset='utf8' ) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = ''' -- 創建表 create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null); -- 插入數據 insert into userinfo(username,password) values('chao','666'),('sb1','222'); ''' cursor.execute(sql) conn.commit() cursor.close() conn.close()

Python 的名為 webauth.py 文件,內容如下:

#對用戶名和密碼進行驗證 def auth(username,password): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='db1', charset='utf8' ) print('userinfo',username,password) cursor = conn.cursor(pymysql.cursors.DictCursor) sql = 'select * from userinfo where username=%s and password=%s;' res = cursor.execute(sql, [username, password]) if res: return True else: return False

用戶輸入用戶名和密碼的文件,名為 web.html,內容如下:

Title 用戶名 密碼

用戶驗證成功后跳轉的頁面,顯示成功,名為 websuccess.html,內容如下:

Title 寶貝兒,恭喜你登陸成功啦

Python 服務端代碼(主邏輯代碼),名為 web_python.py:

from urllib.parse import parse_qs from wsgiref.simple_server import make_server import webauth def application(environ, start_response): # start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')]) # start_response('200 OK', [('Content-Type', 'text/html'),('charset','utf-8')]) start_response('200 OK', [('Content-Type', 'text/html')]) print(environ) print(environ['PATH_INFO']) path = environ['PATH_INFO'] #用戶獲取login頁面的請求路徑 if path == '/login': with open('web.html','rb') as f: data = f.read() #針對form表單提交的auth路徑,進行對應的邏輯處理 elif path == '/auth/': #登陸認證 #1.獲取用戶輸入的用戶名和密碼 #2.去數據庫做數據的校驗,查看用戶提交的是否合法 # user_information = environ[''] if environ.get("REQUEST_METHOD") == "POST": #獲取請求體數據的長度,因為提交過來的數據需要用它來提取,注意POST請求和GET請求的獲取數據的方式不同 try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 #POST請求獲取數據的方式 request_data = environ['wsgi.input'].read(request_body_size) print('>>>>>',request_data) # >>>>> b'username=chao&password=123',是個bytes類型數據 print('?????',environ['QUERY_STRING']) #????? 空的,因為post請求只能按照上面這種方式取數據 #parse_qs可以幫我們解析數據 re_data = parse_qs(request_data) print('拆解后的數據',re_data) #拆解后的數據 {b'password': [b'123'], b'username': [b'chao']} #post請求的返回數據我就不寫啦 pass if environ.get("REQUEST_METHOD") == "GET": #GET請求獲取數據的方式,只能按照這種方式取 print('?????',environ['QUERY_STRING']) #????? username=chao&password=123,是個字符串類型數據 request_data = environ['QUERY_STRING'] # parse_qs可以幫我們解析數據 re_data = parse_qs(request_data) print('拆解后的數據', re_data) #拆解后的數據 {'password': ['123'], 'username': ['chao']} username = re_data['username'][0] password = re_data['password'][0] print(username,password) #進行驗證: status = webauth.auth(username,password) if status: # 3.將相應內容返回 with open('websuccess.html','rb') as f: data = f.read() else: data = b'auth error' # 但是不管是post還是get請求都不能直接拿到數據,拿到的數據還需要我們來進行分解提取,所以我們引入urllib模塊來幫我們分解 #注意昂,我們如果直接返回中文,沒有給瀏覽器指定編碼格式,默認是gbk,所以我們需要gbk來編碼一下,瀏覽器才能識別 # data='登陸成功!'.encode('gbk') else: data = b'sorry 404!,not found the page' return [data] #和咱們學的socketserver那個模塊很像啊 httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()

把代碼拷走,創建文件,放到同一個目錄下,運行一下 we_python.py 文件的代碼就能看到效果。注意先輸入的網址是 127.0.0.1:8080/login ,還要注意你的 MySQL 數據庫沒有問題。


 

十、起飛版 Web 框架

我們上一個 Web 框架把所有的代碼都寫在了一個 py 文件中,我們拆到其他文件里面去,并且針對不用的路徑來進行分發請求的時候都用的 if 判斷,很多值得優化的地方,好,結合我們前面幾個版本的優勢我們來優化一下,分幾個文件和文件夾。

文件的目錄結構為:

web_framework/ ├── templates/ # 用于存放 HTML 文檔 | ├── index.html/ | ├── web.html/ | ├── websuccess.html/ ├── manage.py/ # 主應用 ├── model.py/ # 數據庫相關操作 ├── urls.py/ # ├── views.py/ └── webauth.py/

首先是三個 HTML 文件。

index.html

Title 請登錄

分享到:
標簽:框架
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定