web服務器進階
- 2019 年 10 月 6 日
- 筆記
1、實現自己指定端口運行我們的web服務器
如果我們的web服務器端口被佔用,那麼我們的web服務器直接掛掉。
怎麼實現?我們可以在執行的時候指定一個端口。
複習:
創建一個Demo.py
寫上:
import sys
print(sys.argv)
我們在黑窗口運行一個python文件的時候,執行命令:
python Demo 123 456
會輸出:['Demo.py', '123', '456']
可見,我們是可以給一個程序傳遞參數的。我們用這個功能,來給我們的web服務器指定端口和框架。
2、利用1中的例子,再給一個框架名,讓他直接傳一個框架進入。
我們希望運行 python web服務器 7891 Demo:application
來實現調用Demo框架的application方法。
3、寫一個配置文件,將web服務器中的尋找文件的路徑寫進去。
解決上面三個問題才是真的解耦。
思路已經提供給大家,並且看基礎是能夠寫出來的。
接下來我們利用裝飾器完成路由功能。對裝飾器不懂的可以看看這篇文章:python基礎三
什麼是路由功能?
就是請求的url,我們上次通過if判斷來寫的,很噁心,用另一種方法些
我們將Demo框架寫成這樣(不用再修改web服務器了):
URL_FUNC_DICT = dict()
def url_func(url):
def set_fun(func):
URL_FUNC_DICT[url] = func
def call_func(*args,**kwargs):
return func(*args,**kwargs)
return call_func
return set_fun
@url_func('/login.py')
def login():
# 這裡也可以讀取文件
return '<h1>登錄的頁面</h1>'
@url_func('/create.py')
def create():
return '<h1>註冊的頁面</h1>'
def application(evairon,start_response):
# 第一個參數返回狀態碼,第二個以鍵值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
# 返回給網頁的內容
try:
file_name = evairon['path_info']
fun = URL_FUNC_DICT[file_name]
return fun()
except Exception as e:
return '未找到文件'
偽靜態實現
在前面說過我們只是暫時任務請求以.py結尾的url為動態的。實際上不是這樣。
上面才是動態網頁?
靜態的:域名/index.html
動態的:域名/index.aspx?page=xxx&xxxxx=xxxx,
偽靜態:域名/cour/index.html
web服務器實現偽靜態:
修改web服務器中判斷是.py結尾為以.html結尾,其它不用管。
修改Demo框架中裝飾器的參數為.html結尾。
給Demo框架連接數據庫並顯示到頁面
數據庫運用我們mysql教程中給大家演示的那個student數據庫。
對於python操作數據庫沒了解的請去看mysql數據庫系列文章。
mysql簡單基礎,我們在Demo新創建一個mysqldata方法,並且加上裝飾器
@url_func('/mysqldata.html')
def mysqldata():
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
cursor.execute("select * from studentinfo")
text = cursor.fetchall()
cursor.close()
conn.close()
return str(text)
在瀏覽器中輸入127.0.0.1:端口號/mysqldata.html即可看到內容。
查出來是這樣的:((1, '張三', 1, '男', 23, '武漢', b'x00'), (2, '小花', 2, '女', 20, '長沙', b'x00'), (3, '李四', 3, '男', 21, '上海', b'x00'), (4, '小貓', 1, '女', 18, '北京', b'x00'), (6, '小狗', 3, '女', 25, '成都', b'x00'), (7, '趙六', 1, '男', 26, '天津', b'x00'))
看着很噁心,給個格式。修改mysqldata方法:
這裡會用到html的知識點,希望自己補充。修改成:
@url_func('/mysqldata.html')
def mysqldata():
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
cursor.execute("select * from studentinfo")
text = cursor.fetchall()
cursor.close()
conn.close()
html = "<table border='1' width = '400px' cellspacing='0' cellpadding='0'>"
tr_html = '''
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
</tr>
'''
for item in text:
html += tr_html %(item[0],item[1],item[2],item[3],item[4],item[5],item[6])
html +="</table>"
return str(html)
這樣就好看多了。當然你想顯示什麼就數據庫查什麼就好了。
完善Demo框架
1、給路由添加正則
現在我們的url返回的都是固定的,比如我們想要刪除一個數據,請求的url為/delete/xxx.html
我們需要傳遞一個xxx,表示id,這個id是不確定的,所以我們需要正則匹配,只要是這種格式,我們都執行
delete方法。修改如下:
修改application方法:
def application(evairon,start_response):
# 第一個參數返回狀態碼,第二個以鍵值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
# 返回給網頁的內容
try:
file_name = evairon['path_info']
for url,func in URL_FUNC_DICT.items():
# 匹配是否有這個函數,有返回回去
ret = re.match(url,file_name)
if ret:
return func(ret)
except Exception as e:
return '未找到文件 %s'%e
添加delete方法,並匹配所有url為/delete/xxx.html格式的都執行該方法。
@url_func(r'/delete/(d+).html')
def delete(ret):
return '刪除方法。ok'
由於給所有函數傳遞了一個url,所以需要給上面的函數都添加一個參數。
執行:成功返回刪除方法。ok,那我們繼續完善刪除方法。
@url_func(r'/delete/(d+).html')
def delete(ret):
# 獲取id值
id = ret.group(1)
# 執行sql刪除
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
count = cursor.execute("delete from studentinfo where studentid = %s",(id,))
if count:
conn.commit()
cursor.close()
conn.close()
return '刪除成功。ok!!'
else:
return '刪除失敗!'
其他修改啊,添加,只是sql語句不同,都大同小異。
不過在修改的時候要修改正則,傳給數據的還要有修改值沒有了解post請求就換個正則匹配
比如127.0.0.1/修改方法/要修改的id/要修改的內容.html,用正則匹配出id和要修改的內容就可以了。
但是有個問題,當我們傳遞的內容或者漢子的時候會出現亂碼,因為是通過url傳遞的,中途會有個url編碼的過程,
我們需要解碼:
1、需要導入模塊
import urllib
解碼:urllib.parse.unquote()
編碼:urllib.parse.quote()
添加日誌模塊
不會日誌模塊需要看基礎:python常用模塊二
導入日誌模塊:import logging
修改application方法:
def application(evairon,start_response):
# 第一個參數返回狀態碼,第二個以鍵值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
file_name = evairon['path_info']
# 寫入日誌
logging.basicConfig(level=logging.INFO,
filename = './log.txt',
filemode = 'a',
format = '%(asctime)s – %(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s'
)
logging.info('訪問了%s'%file_name)
# 返回給網頁的內容
try:
for url,func in URL_FUNC_DICT.items():
# 匹配是否有這個函數,有返回回去
ret = re.match(url,file_name)
if ret:
return func(ret)
except Exception as e:
logging.WARNING('找不到文件')
return '未找到文件 %s'%e