web框架的本質:socket服務端與瀏覽器的通訊 socket服務端功能劃分: 1.負責與瀏覽器收發消息(socket通訊) --》wsgiref/uWsgi/gunicorn等web服務網關接口和服務器 2.根據用戶訪問不一樣的路徑執行不一樣的函數 --》路由系統(url與函數的對應關係) 3.從HTML讀取出內容而且完成字符串的替換 --》jinja2(模板語言)
""" 這是一個靜態的web網站,返回什麼數據類型就是什麼,而如今網站都是動態的。 """ import socket def f1(request): """ 處理用戶請求,並返回相應的內容 :param request: 用戶請求的全部信息 :return: """ # 讀取本地二進制文件並返回(在這裏是本身寫模板,能夠任意後綴名文件並不必定須要html後綴) f = open('index.fsw','rb') data = f.read() f.close() return data def f2(request): f = open('aricle.tpl','rb') data = f.read() f.close() return data # 路由與函數的對應關係(路由系統) routers = [ ('/xxx', f1), ('/ooo', f2), ] def run(): # 獲取socket對象 sock = socket.socket() # 綁定ip地址和端口 sock.bind(('127.0.0.1',8080)) # 開始監聽(設置最大監聽數5個) sock.listen(5) while True: conn,addr = sock.accept() # 夯住,等待用戶鏈接 # 獲取用戶發送的數據 data = conn.recv(8096) # 直接轉換爲字符串 data = str(data,encoding='utf-8') print(data) # 根據http協議劃分請求頭和請求體\r\n\r\n headers,bodys = data.split('\r\n\r\n') # 根據已有的http協議數據結構切分元素 temp_list = headers.split('\r\n') # 分別獲取請求方法、請求url地址、請求協議類型 method,url,protocal = temp_list[0].split(' ') conn.send(b"HTTP/1.1 200 OK\r\n\r\n") func_name = None # 設置標誌位 for item in routers: # 遍歷url與函數對應關係表,並判斷當前請求url是否相等 if item[0] == url: # 能對應就獲取函數名並中止循環 func_name = item[1] break if func_name: # 有這個函數就加括號調用並傳入參數 response = func_name(data) else: response = b"404" # 返回函數處理後的結果 conn.send(response) conn.close() if __name__ == '__main__': run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用戶名</th> <th>郵箱</th> </tr> </thead> <tbody> <tr> <th>1</th> <th>root</th> <th>root@qq.com</th> </tr> </tbody> </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>用戶登陸</h1> <form> <p><input type="text" placeholder="用戶名" /></p> <p><input type="password" placeholder="密碼" /></p> </form> </body> </html>
"""動態網站則是在靜態網站的基礎之上,進行字符串的替換,以完成網站頁面的實時更新效果""" import socket def f1(request): """ 處理用戶請求,並返回相應的內容 :param request: 用戶請求的全部信息 :return: """ f = open('index.fsw','rb') data = f.read() f.close() return data def f2(request): """ 運用時間戳的方式,初步實現動態網站 :param request: :return: """ f = open('aricle.tpl','r',encoding='utf-8') data = f.read() f.close() import time # 獲取時間戳 ctime = time.time() # 調用字符串的replace()替換方法換成時間戳,頁面每次刷新顯示的數據都不同 data = data.replace('@@sw@@',str(ctime)) # 返回bytes()類型數據 return bytes(data,encoding='utf-8') def f3(request): """ 獲取數據庫數據,只要數據庫數據有更新,則頁面刷新以後都會顯示 :param request: 用戶請求的信息 :return: """ import pymysql # 建立鏈接對象 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu') # 獲取遊標 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 執行sql語句查詢數據庫數據 cursor.execute("select id,username,password from userinfo") # 獲取表中全部數據 user_list = cursor.fetchall() # 關閉遊標對象 cursor.close() # 關閉鏈接對象 conn.close() content_list = [] for row in user_list: # 遍歷數據庫查詢的數據,拼接字符串 tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password']) # 把拼接的字符串添加到列表 content_list.append(tp) # 調用.join方法把列表轉換爲字符串 content = "".join(content_list) f = open('userlist.html','r',encoding='utf-8') template = f.read() f.close() # 模板渲染(模板+數據)完成字符串的替換 data = template.replace('@@sdfsdffd@@',content) return bytes(data,encoding='utf-8') def f4(request): """ 調用第三方模塊,實現頁面模板的渲染 :param request: :return: """ import pymysql # 建立鏈接對象 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu') # 獲取遊標 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 執行sql語句查詢數據庫數據 cursor.execute("select id,username,password from userinfo") # 獲取表中全部數據 user_list = cursor.fetchall() # 關閉遊標對象 cursor.close() # 關閉鏈接對象 conn.close() f = open('hostlist.html','r',encoding='utf-8') data = f.read() f.close() # 基於第三方工具實現的模板渲染 from jinja2 import Template template = Template(data) # 調用render()方法完成字符串的替換,這裏要注意,先後端特殊語法要相同 data = template.render(user_list=user_list,user='sdfsdfsdf') return data.encode('utf-8') # 路由與函數的對應關係 routers = [ ('/xxx', f1), ('/ooo', f2), ('/userlist.htm', f3), ('/host.html', f4), ] def run(): # 獲取socket對象 sock = socket.socket() # 綁定ip地址和端口 sock.bind(('127.0.0.1',8080)) # 開始監聽(設置最大監聽數5個) sock.listen(5) while True: conn,addr = sock.accept() # 夯住,等待用戶鏈接 # 獲取用戶發送的數據 data = conn.recv(8096) # 直接轉換爲字符串 data = str(data,encoding='utf-8') # 根據http協議劃分請求頭和請求體\r\n\r\n headers,bodys = data.split('\r\n\r\n') # 根據已有的http協議數據結構切分元素 temp_list = headers.split('\r\n') # 分別獲取請求方法、請求url地址、請求協議類型 method,url,protocal = temp_list[0].split(' ') conn.send(b"HTTP/1.1 200 OK\r\n\r\n") func_name = None # 設置標誌位 for item in routers: # 遍歷url與函數對應關係表,並判斷當前請求url是否相等 if item[0] == url: # 能對應就獲取函數名並中止循環 func_name = item[1] break if func_name: # 有這個函數就加括號調用並傳入參數 response = func_name(data) else: response = b"404" # 返回函數處理後的結果 conn.send(response) conn.close() if __name__ == '__main__': run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用戶名</th> <th>郵箱</th> </tr> </thead> <tbody> <tr> <th>1</th> <!-- 自定義字符串替換的特殊語法 --> <th>@@sw@@</th> <th>root@qq.com</th> </tr> </tbody> </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用戶名</th> <th>郵箱</th> </tr> </thead> <tbody> {% for row in user_list %} <!--使用第三方模板,就要遵循他的語法規則--> <tr> <td>{{row.id}}</td> <td>{{row.username}}</td> <td>{{row.password}}</td> </tr> {% endfor %} </tbody> </table> {{user}} </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>用戶登陸</h1> <form> <p><input type="text" placeholder="用戶名" /></p> <p><input type="password" placeholder="密碼" /></p> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用戶名</th> <th>郵箱</th> </tr> </thead> <tbody> <!--自定義模板特殊語法--> @@sdfsdffd@@ </tbody> </table> </body> </html>
有以上咱們模擬網站(socket服務端)和瀏覽器(socket客戶端)的知識知道了: 1.http是創建在tcp之上的,無狀態的,短連接,一次請求一次響應。 而TCP是不斷開的長鏈接。 2.http協議是固定的鍵值對組合,每一個鍵值對之間由\r\n分割,請求頭和請求體之間則是由兩個\r\n\r\n分割。而響應頭和響應體也是這樣的組合。 3.本身寫的網站必須具有如下要素: a.socket服務端 b.根據url的不一樣,返回不一樣的內容(url與函數的對應關係) c.返回字符串給用戶(模板引擎渲染:HTML充當模板和特殊字符,本身定義任意數據) 而web框架的種類也是根據以上三點相結合: 框架自帶a,b,c Tornado [第三方a],b,c wsgiref服務網關接口、Django [第三方a],b,[第三方c] wsgiref服務網關接口、Flask、jinja2模板 按照另外一種維度劃分: 重量級:Django 輕量級:Tornado、Flask