Djangocss
全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端,基於請求作出響應,客戶都先請求,服務端作出對應的響應,按照http協議的請求協議發送請求,服務端按照http協議的響應協議來響應請求,這樣的網絡通訊,咱們就能夠本身實現Web框架了。html
基於socket來本身實現一個web框架,寫一個web服務端,讓瀏覽器來請求,並經過本身的服務端把頁面返回給瀏覽器,瀏覽器渲染出咱們想要的效果。 前端
1、簡單的web框架python
import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() conn,addr = sk.accept() msg = conn.recv(1024) str_msg = msg.decode('utf-8') print(str_msg) conn.send(b'HTTP/1.1 200 ok \r\n\r\n') conn.send(b'hello world') conn.close() sk.close()
在瀏覽器訪問服務端:mysql
重啓咱們的代碼,而後在網址中輸入這個:web
瀏覽器發過來一堆的消息,咱們給瀏覽器回覆(響應)信息的時候,也要按照一個消息格式來寫,這些都是http協議規定的,那麼咱們就來學習一下http協議,而後繼續完善咱們的web框架:sql
HTTP協議:https://www.cnblogs.com/clschao/articles/9230431.html數據庫
2、返回Html文件的web框架:瀏覽器
首先寫一個html文件,內容以下,名稱爲index.html:服務器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> h1{ background-color: green; color: white; } </style> </head> <body> <h1>世界,你好!</h1> <img src="https://img3.chouti.com/img_1557880036293.jpg?imageView2/1/q" alt=""> <script> alert('這是咱們第一個網頁') </script> </body> </html>
準備咱們的python代碼,服務端程序,文件內容以下,文件名稱爲 返回Html文件的web框架.py :
import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() conn,addr = sk.accept() msg = conn.recv(1024) str_msg = msg.decode('utf-8') print('瀏覽器請求信息:',str_msg) conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.html','rb') as f: data = f.read() conn.send(data) conn.close() sk.close()
import socket from threading import Thread server = socket.socket() server.bind(('0.0.0.0',8001)) server.listen() def communication(conn): #接受請求數據 msg = conn.recv(1024).decode('utf-8') print(msg) #組合響應協議的消息格式,而後發送響應信息 conn.send(b'HTTP/1.1 200 ok \r\n\r\n') #打開index.html文件,返回給前端 with open('index.html', 'rb') as f: #沒有引入文件形式的html頁面 data = f.read() conn.send(data) conn.close() while 1: #接受鏈接 conn, add = server.accept() #開啓線性併發 t = Thread(target=communication,args=(conn,)) t.start()
頁面上輸入網址看效果:css樣式和js效果都有。
將index.html 文件中css樣式與js語句寫成文件,圖片網絡地址改成本地地址(01.jpg):
index.css:
h1{ background-color: green; color: white; }
index.js
alert('這是咱們第一個網頁')
index.html改成:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> <!--<style>--> <!--h1{--> <!--background-color: green;--> <!--color: white;--> <!--}--> <!--</style>--> </head> <body> <h1>世界,你好!</h1> <img src="01.jpg" alt=""> <!--<script>--> <!--alert('這是咱們第一個網頁')--> <!--</script>--> <script src="index.js"></script> </body> </html>
一樣使用咱們以前的python程序,來看效果:
須要將html頁面須要的css、js、圖片等文件也發送給瀏覽器就,而且這些靜態文件都是瀏覽器單獨過來請求的,其實和標籤的屬性有有關係,css文件是link標籤的href屬性:<link rel="stylesheet" href="test.css">,js文件是script標籤的src屬性:<script src="test.js"></script>,圖片文件是img標籤的src屬性:<img src="meinv.png" alt="" width="100" height="100"> ,那個.ico文件是link標籤的屬性:<link rel="icon" href="wechat.ico">,其實這些屬性都會在頁面加載的時候,單獨到本身對應的屬性值裏面取請求對應的文件數據,並且咱們若是在值裏面寫的都是本身本地的路徑,那麼都會來本身的本地路徑來找,若是咱們寫的是相對路徑,就會到咱們本身的網址+文件名稱,這個路徑來找它須要的文件,因此咱們只須要將這些請求作一些響應,將對應的文件數據相應給瀏覽器就能夠了!
3、返回靜態文件的高級web框架
服務端程序:
import socket sk = socket.socket() sk.bind(('127.0.0.1',8001)) sk.listen() while 1: conn,addr = sk.accept() msg = conn.recv(1024) str_msg = msg.decode('utf-8') path = str_msg.split('\r\n')[0].split(' ')[1] conn.send(b'HTTP/1.1 200 ok \r\n\r\n') if path == '/': print(msg.decode('utf-8')) with open('index.html','rb') as f: data = f.read() conn.send(data) conn.close() elif path == '/01.jpg': with open('01.jpg','rb') as f: pic_data = f.read() conn.send(pic_data) conn.close() elif path == '/index.css': with open('index.css','rb') as f: css_data = f.read() conn.send(css_data) conn.close() elif path == '/wechat.ico': with open('wechat.ico','rb') as f: ico_data = f.read() conn.send(ico_data) conn.close() elif path == '/index.js': with open('index.js','rb') as f: js_data = f.read() conn.send(js_data) conn.close()
index.html:添加了<link rel="icon" href="wechat.ico">屬性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> <link rel="icon" href="wechat.ico"> <!--<style>--> <!--h1{--> <!--background-color: green;--> <!--color: white;--> <!--}--> <!--</style>--> </head> <body> <h1>世界,你好!</h1> <img src="01.jpg" alt=""> <!--<script>--> <!--alert('這是咱們第一個網頁')--> <!--</script>--> <script src="index.js"></script> </body> </html>
import socket from threading import Thread server = socket.socket() server.bind(('0.0.0.0',8001)) server.listen() def communication(conn): msg = conn.recv(1024).decode('utf-8') print(msg) path = msg.split('\r\n')[0].split(' ')[1] print(path) #針對不一樣的請求路徑,返回不一樣的文件 if path =='/': conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n') with open('index.html', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path =='/index.css': conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n') with open('index.css', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path =='/index.js': conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n') with open('index.js', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path =='/wechat.ico': conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n') with open('wechat.ico', 'rb') as f: data = f.read() conn.send(data) conn.close() elif path =='/01.jpg': conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n') with open('01.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() while 1: conn, add = server.accept() t = Thread(target=communication,args=(conn,)) t.start()
四:函數多線程版返回靜態文件的web框架
靜態文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico
python代碼:
import socket from threading import Thread server = socket.socket() server.bind(('127.0.0.1',8001)) server.listen() def html(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.html', 'rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.css','rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.js', 'rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('wechat.ico','rb') as f: data = f.read() conn.send(data) conn.close() def jpg(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('01.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() urlpatterns = [ ('/',html), ('/index.css',css), ('/index.js',js), ('/wechat.ico',ico), ('/01.jpg',jpg), ] def communication(conn): msg = conn.recv(1024).decode('utf-8') print(msg) path = msg.split('\r\n')[0].split(' ')[1] print(path) #針對不一樣的請求路徑,返回不一樣的文件 for urlpattern in urlpatterns: if urlpattern[0] == path: # urlpattern[1](conn) # 多線程執行函數 t = Thread(target=urlpattern[1],args=(conn,)) t.start() # if path =='/': # html(conn) # elif path =='/index.css': # css(conn) # elif path =='/index.js': # js(conn) # elif path =='/wechat.ico': # ico(conn) # elif path =='/01.jpg': # jpg(conn) while 1: conn, add = server.accept() t = Thread(target=communication,args=(conn,)) t.start()
5、返回不一樣html頁面的web框架
靜態文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico
添加返回的頁面 home.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首頁</h1> <h1>time</h1> </body> </html>
python代碼:
import socket from threading import Thread server = socket.socket() server.bind(('0.0.0.0',8001)) server.listen() def html(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.html', 'rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.css', 'rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.js', 'rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('wechat.ico', 'rb') as f: data = f.read() conn.send(data) conn.close() def jpg(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('01.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() def home(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('home.html', 'rb') as f: data = f.read() conn.send(data) conn.close() urlpatterns = [ ('/',html), ('/index.css',css), ('/index.js',js), ('/wechat.ico',ico), ('/01.jpg',jpg), ('/home.html',home), ] def communication(conn): msg = conn.recv(1024).decode('utf-8') # print(msg) path = msg.split('\r\n')[0].split(' ')[1] #針對不一樣的請求路徑,返回不一樣的文件 for urlpattern in urlpatterns: # print(path) if urlpattern[0] == path: # urlpattern[1](conn) # 多線程執行函數 t = Thread(target=urlpattern[1],args=(conn,)) t.start() while 1: conn, add = server.accept() t = Thread(target=communication,args=(conn,)) t.start()
6、返回動態l頁面的web框架
靜態文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico ,home.html
python 代碼:
import time import socket from threading import Thread server = socket.socket() server.bind(('0.0.0.0',8001)) server.listen() def html(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.html','rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.css','rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('index.js','rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('wechat.ico','rb') as f: data = f.read() conn.send(data) conn.close() def jpg(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') with open('01.jpg', 'rb') as f: data = f.read() conn.send(data) conn.close() def home(conn): conn.send(b'HTTP/1.1 200 ok \r\n\r\n') current_time = str(time.time()) with open('home.html','r',encoding='utf-8') as f: data = f.read() data = data.replace('time',current_time) conn.send(data.encode('utf-8')) conn.close() urlpatterns = [ ('/',html), ('/index.css',css), ('/index.js',js), ('/favicon.ico',ico), ('/01.jpg',jpg), ('/home.html',home), ] def communication(conn): msg = conn.recv(1024).decode('utf-8') # print(msg) path = msg.split('\r\n')[0].split(' ')[1] #針對不一樣的請求路徑,返回不一樣的文件 for urlpattern in urlpatterns: # print(path) if urlpattern[0] == path: # urlpattern[1](conn) # 多線程執行函數 t = Thread(target=urlpattern[1],args=(conn,)) t.start() while 1: conn, add = server.accept() t = Thread(target=communication,args=(conn,)) t.start()
7、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開發環境用的就是這個模塊來作服務器。
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>'] httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()
簡單wsgiref模塊版web框架:
靜態文件使用:index.html , home.html
import time from wsgiref.simple_server import make_server def app(environ,start_response): start_response('200 OK', [('Content-Type', 'text/html'), ('k1', 'v1')]) print(environ) path = environ['PATH_INFO'] for urlpattern in urlpatterns: print(path) if urlpattern[0] == path: ret = urlpattern[1]() return ret def html(): with open('index.html', 'rb') as f: data = f.read() return [data] def home(): current_time = str(time.time()) with open('home.html', 'r',encoding='utf-8') as f: data = f.read() data = data.replace('time',current_time).encode('utf-8') return [data] urlpatterns = [ ('/',html), ('/home.html',home), ] httpd = make_server('127.0.0.1', 8001, app) httpd.serve_forever()
一個完整的web項目,用戶登陸認證的項目,須要鏈接數據庫,在mysql數據庫裏面準備一些表和數據:
mysql> create database day53; Query OK, 1 row affected (0.12 sec) mysql> use day53; 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.36 sec) mysql> insert into userinfo(username,password) values('xu','123'),('wu','456'); Query OK, 2 rows affected (0.17 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from userinfo; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | xu | 123 | | 2 | wu | 456 | +----+----------+----------+ 2 rows in set (0.00 sec)
python服務端代碼(主邏輯代碼):
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')]) # print(environ) # print(environ['PATH_INFO']) path = environ['PATH_INFO'] # 用戶獲取login頁面的請求路徑 if path == '/login': with open('login.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.decode('utf-8')) #將bytes類型數據轉碼 print('拆解後的數據',re_data) #拆解後的數據 {'username': ['wu'], 'password': ['456']} username = re_data['username'][0] password = re_data['password'][0] print(username,password) # 進行驗證 status = webauth.auth(username,password) if status: # 3.將相應內容返回 with open('success.html','rb') as f: data = f.read() else: data = b'auth error' if environ.get("REQUEST_METHOD") == "GET": # GET請求獲取數據的方式,只能按照這種方式取 print('?????',environ['QUERY_STRING']) #????? username=xu&password=123,是個字符串類型數據 request_data = environ['QUERY_STRING'] print('>>>>request_data', request_data) # parse_qs能夠幫咱們解析數據 re_data = parse_qs(request_data) print('拆解後的數據', re_data) username = re_data['username'][0] password = re_data['password'][0] print(username,password) # 進行驗證 status = webauth.auth(username,password) if status: # 3.將相應內容返回 with open('success.html','rb') as f: data = f.read() else: data = b'auth error' # 不論是post仍是get請求都不能直接拿到數據,拿到的數據還須要咱們來進行分解提取,因此咱們引入urllib模塊來幫咱們分解 else: data = b'sorry 404!,not found the page' return [data] httpd = make_server('127.0.0.1', 8001, application) print('Serving HTTP on port 8001...') # 開始監聽HTTP請求: httpd.serve_forever()
登錄頁面 login.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--form標籤中 method屬性能夠等於get--> <form action="http://127.0.0.1:8001/auth/" method="post"> 用戶名<input type="text" name="username"> 密碼 <input type="password" name="password"> <input type="submit"> </form> </body> </html>
用戶驗證 webauth.py文件:
def auth(username,password):
import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='day53', 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
用戶登錄成功跳轉 success.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>恭喜登錄成功!</h1> </body> </html>
一個比較low的文件配置版web框架:
1.pycharm建立userinfo表格:
#建立表,插入數據 def createtable(): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='day53', 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()
2.框架主體:
from urls import urlpatterns from wsgiref.simple_server import make_server #這個文件裏面是框架的主體內容 def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) path = environ['PATH_INFO'] for url_tuple in urlpatterns: if url_tuple[0] == path: data = url_tuple[1](environ) #environ要傳進去,由於處理邏輯裏面可能要用 break else: data = b'sorry 404!,not found the page' return [data] #注意昂,咱們若是直接返回中文,沒有給瀏覽器指定編碼格式,默認是gbk,因此咱們須要gbk來編碼一下,瀏覽器才能識別 # data='登錄成功!'.encode('gbk') httpd = make_server('127.0.0.1', 8001, application) print('Serving HTTP on port 8001...') # 開始監聽HTTP請求: httpd.serve_forever() #整個框架寫好了,那麼咱們未來想添加一些新的功能,好比說有人想在網址裏面輸入http://127.0.0.1:8001/timer 來查看當前時間,你只須要兩步,寫一個url映射關係,寫一個應對的處理函數就搞定了,有了框架就不須要你在從新寫一遍這全部的邏輯了,簡單兩步搞定新功能
3.urls文件:
from views import login,auth,favicon,index,timer #url與視圖函數的對應關係 urlpatterns=[ ('/login',login), ('/auth/',auth), ('/favicon.ico',favicon), ('/',index), ('/timer',timer), ]
4.views文件:
import datetime import webauth from urllib.parse import parse_qs def login(environ): with open('templates/login.html', 'rb') as f: data = f.read() return data def auth(environ): # 登錄認證 # 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.decode('utf-8')) # 將bytes類型數據轉碼 print('拆解後的數據', re_data) # 拆解後的數據 {'username': ['wu'], 'password': ['456']} username = re_data['username'][0] password = re_data['password'][0] print(username, password) # 進行驗證 status = webauth.auth(username, password) if status: # 3.將相應內容返回 with open('success.html', 'rb') as f: data = f.read() else: data = b'auth error' 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('templates/websuccess.html', 'rb') as f: data = f.read() else: data = b'auth error' return data def favicon(environ): with open('wechat.ico','rb') as f: data = f.read() return data def index(environ): with open('templates/index.html','rb') as f: data = f.read() return data #查看當前時間的 def timer(environ): data = str(datetime.datetime.now()).encode('utf-8') return data
5.用戶名密碼驗證 webauth文件:
#對用戶名和密碼進行驗證 def auth(username,password): import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', database='day53', 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
6.templates 文件夾下html文件:
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="http://127.0.0.1:8001/login">請登陸</a> </body> </html>
login.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--若是form表單裏面的action什麼值也沒給,默認是往當前頁面的url上提交你的數據,因此咱們能夠本身指定數據的提交路徑--> <!--<form action="http://127.0.0.1:8001/auth/" method="post">--> <form action="http://127.0.0.1:8001/auth/" method="get"> 用戶名<input type="text" name="username"> 密碼 <input type="password" name="password"> <input type="submit"> </form> </body> </html>
websuccess.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> h1{ color:red; } </style> </head> <body> <h1>恭喜你登錄成功!</h1> </body> </html>
上面的代碼實現了一個簡單的動態頁面(字符串替換),我徹底能夠從數據庫中查詢數據,而後去替換我html中的對應內容(專業名詞叫作模板渲染,你先渲染一下,再給瀏覽器進行渲染),而後再發送給瀏覽器完成渲染。 這個過程就至關於HTML模板渲染數據。 本質上就是HTML內容中利用一些特殊的符號來替換要展現的數據。 我這裏用的特殊符號是我定義的,其實模板渲染有個現成的工具: jinja2
下載:在cmd命令提示符中輸入或者pycharm中terminal
pip install jinja2
來一個html文件,index,html,內容以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>愛好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
使用jinja2渲染index2.html文件,建立一個python文件:
from wsgiref.simple_server import make_server
from jinja2 import Template
def index():
with open("index.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'] # 取到用戶輸入的url
func = None # 將要執行的函數
for i in URL_LIST:
if i[0] == url:
func = i[1] # 去以前定義好的url列表裏找url應該執行的函數
break
if func: # 若是能找到要執行的函數
return func() # 返回函數的執行結果
else:
return [bytes("404沒有該頁面", encoding="utf8"), ]
if __name__ == '__main__':
httpd = make_server('', 8001, run_server)
print("Serving HTTP on port 8001...")
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;
模板的原理就是字符串替換,咱們只要在HTML頁面中遵循jinja2的語法規則寫上,其內部就會按照指定的語法進行相應的替換,從而達到動態的返回內容。