DIY一個web框架
阿新 • • 發佈:2021-11-10
web框架
Web框架(Web framework)是一種開發框架,用來支援動態網站、網路應用和網路服務的開發。這大多數的web框架提供了一套開發和部署網站的方式,也為web行為提供了一套通用的方法。web框架已經實現了很多功能,開發人員使用框架提供的方法並且完成自己的業務邏輯,就能快速開發web應用了。瀏覽器和伺服器的是基於HTTP協議進行通訊的。也可以說web框架就是在以上十幾行程式碼基礎張擴展出來的,有很多簡單方便使用的方法,大大提高了開發的效率。
wsgiref模組
最簡單的Web應用就是先把HTML用檔案儲存好,用一個現成的HTTP伺服器軟體,接收使用者請求,從檔案中讀取HTML,返回。
如果要動態生成HTML,就需要把上述步驟自己來實現。不過,接受HTTP請求、解析HTTP請求、傳送HTTP響應都是苦力活,如果我們自己來寫這些底層程式碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。
正確的做法是底層程式碼由專門的伺服器軟體實現,我們用Python專注於生成HTML文件。因為我們不希望接觸到TCP連線、HTTP原始請求和響應格式,所以,需要一個統一的介面協議來實現這樣的伺服器軟體,讓我們專心用Python編寫Web業務。這個介面就是WSGI:Web Server Gateway Interface。而wsgiref模組就是python基於wsgi協議開發的服務模組。
from wsgiref.simple_server import make_server def application(environ, start_response): # 按著http協議解析資料:environ---請求 # 按著http協議組裝資料:start_response---響應 # print(environ) # print(type(environ)) # <class 'dict'> start_response("200 OK", [("Content-type", "text-html")]) # 這個格式是固定的,必須是這樣(響應狀態碼, [(響應頭), (響應頭)...])# 得到請求路徑 path = environ.get("PATH_INFO") # 對請求路徑進行判斷 if path == "/login": return [b"<h1>login</h1>"] # 返回必須是列表型別 elif path == "/index": return [b"<h1>index</h1>"] # 返回必須是列表型別 else: return [b"<h1>hello world</h1>"] # 返回必須是列表型別 # 封裝socket httped = make_server("", 8090, application) # 等待使用者連線:conn, addr = sock.accept() httped.serve_forever() # 會呼叫application(environ, start_response)
DIY一個web框架
models.py
# 在資料庫生成使用者表,在專案執行前只需執行一次即可,把所有建立資料表的操作都放在此檔案即可 import pymysql conn = pymysql.connect( host="127.0.0.1", port=3306, user="root", password="123456", db="web", autocommit=True ) cur = conn.cursor() sql = """ create table user_info( id int primary key auto_increnment not null, name varchar(32) not null, pwd varchar(32) not null """ cur.execute(sql) cur.close() conn.close()
main.py
from wsgiref.simple_server import make_server from urls import url_patterns def application(environ, start_response): start_response("200 OK", [("Content-type", "text/html")]) print(environ.get("PATH_INFO")) # 客戶端請求路徑 path = environ.get("PATH_INFO") # 方案1---直接針對路徑做判斷,然後寫業務邏輯程式碼 # if path == "/login": # with open("login.html", "rb") as f: # data = f.read() # return [data] # elif path == "/index": # with open("index.html", "rb") as f: # data = f.read() # return [data] # 方案2---將業務處理邏輯封裝成函式,與路徑一一匹配放在元組,然後用一個列表放置所有的元組 # 這樣就不用頻繁的使用if判斷,而且解耦後,如果想增加一個路徑,只需要新增一個對應檢視函式即可 # 把url_patterns(路由分發)列表放在urls.py # 把檢視函式放在views.py # 把所有html檔案放在templates資料夾下 func = None # 迴圈列表,取出路徑和對應檢視函式地址 for p, f in url_patterns: # 如果瀏覽器請求路徑正確,那麼把路徑對應的檢視函式地址賦值給func if path == p: func = f break # 如果func不為空,那麼執行func,並且把客戶端請求資訊作為引數,返回func執行後的結果給客戶端,如果為空則返回錯誤資訊 if func: return [func(environ)] else: return [b"404 error"] httped = make_server("", 8080, application) httped.serve_forever()
urls.py
from views import *
url_patterns = [ ("/login", login), ("/reg", reg), ("/auth", auth), ]
views.py
import pymysql from urllib.parse import parse_qs def login(environ): with open("templates/login.html", "rb") as f: data = f.read() return data def reg(environ): with open("templates/reg.html", "rb") as f: data = f.read() return data def auth(environ): """ 以下操作是wsgiref模組讀取form表單提交的資料,比Django複雜,但比我們自己處理起來要簡單很多了 :param environ: :return: """ try: request_body_size = int(environ.get("CONTENT_LENGTH", 0)) except (ValueError): request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) data = parse_qs(request_body) user = data.get(b"user")[0].decode("utf8") pwd = data.get(b"pwd")[0].decode("utf8") print(user, pwd) # 操作資料庫 conn = pymysql.connect( host="127.0.0.1", port=3306, user="root", password="123456", db="web", ) cur = conn.cursor() sql = "select * from user_info where name=%s and pwd=%s;" cur.execute(sql, (user, pwd)) # 如果使用者名稱密碼正確,那麼返回index頁面,不正確返回錯誤資訊 if cur.fetchone(): f = open("templates/index.html", "rb") data = f.read() return data else: return b"user or pwd is wrong"
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登入</title> <link rel="icon" href="//www.jd.com/favicon.ico"> </head> <body> <h3>登入頁面</h3> <!--向auth路徑提交form表單--> <form action="http://127.0.0.1:8080/auth" method="post"> <p> 姓名: <input type="text" name="user"> </p> <p> 密碼: <input type="password" name="pwd"> </p> <p> <input type="submit" value="提交"> </p> </form> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> <link rel="icon" href="//www.jd.com/favicon.ico"> </head> <body> <h1>首頁</h1> <img src="https://img0.baidu.com/it/u=2641803730,2025967347&fm=26&fmt=auto" alt=""> </body> </html>
總結
""" web框架功能總結 1. main.py:啟動檔案,封裝了socket 2. urls.py:路徑與檢視函式對映關係---url控制器 3. views.py:檢視函式,固定有一個形式引數environ(所有的請求資訊都在這個引數裡面,請求路徑/請求方式/請求資料...)---檢視函式 4. templates資料夾:html檔案---模板 5. models:在專案啟動前,在資料庫中建立表結構---與資料庫相關 """while True: print('studying...')