一,web應用的介紹
本質:可以通過web訪問的應用程序,一般是B/S模式(用戶通過瀏覽器訪問程序)
優點:
1,操作過程簡單,只需要有了個使用的瀏覽器(Google Chrome)
2,耗費的硬盤空間很少。
3,服務器實時更新。
4,基於B/S開發的應用程序可以很好的結合其他應用程序的功能。
5,可以跨平台使用。
缺點:
1,強調瀏覽器的適用性,若是棄用某些操作平台或版本就會影響大量的客戶。
2,基於互聯網運行,網絡連接出問題時,應用將不能正常使用。
3,由於絕大多數情況不能離線使用,因而損失了很多的靈活性。
4,完全依賴服務商的可及性。公司倒閉了,服務器及不能使用了。
5,提供方公司具有這更大的控制權。
6,公司可以檢索任何用戶的功能,這可能引起隱私安全的問題。
二,關於HTTP協議
HTTP(Hyper Text Transfer Protocol)協議就是超文本傳輸協議,是用於萬維網(WWW:World Wide Web )服務器與本地瀏覽器之間傳輸超文本的傳送協議。規定了客戶端與服務器消息傳輸的格式
特點:
1:基於TCP/ip協議作用於應用層的協議
2:基於請求-響應模式
HTTP協議規定,請求從客戶端發出,最后服務器端響應該請求並 返回。換句話說,肯定是先從客戶端開始建立通信的,服務器端在沒有 接收到請求之前不會發送響應。(請求必定由客戶端發出,二服務器回復相應)
3:無狀態保存
HTTP是一種不保存狀態,即無狀態(stateless)協議。HTTP協議 自身不對請求和響應之間的通信狀態進行保存。也就是說在HTTP這個 級別,協議對於發送過的請求或響應都不做持久化處理。
4:無連接
無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。
請求數據的格式:
1:請求首行
2:請求頭(鍵值對形式)
3:請求體(post攜帶數據)
響應數據的格式:
1:響應首行
2:響應頭(鍵值對形式)
3:相應體(post請求攜帶的數據)
響應碼:
1xx:服務器已經成功接受到你的數據正在處理,你可以繼續提交其他數據
2xx:請求成功 服務器已經將你請求的數據發送給你了
3xx:重指定(連接到第三方網址)
4xx:請求資源不存在
5xx:服務器錯誤
動靜態網頁:
靜態網頁:
頁面上的數據都是寫死的,萬年不變。
動態網頁:
頁面上的數據是從后端動態獲取的。
比如后端獲取當前時間。
后端獲取數據庫然后傳遞給前端給頁面。
模板渲染:
后端生成的數據直接傳遞給前端頁面使用(並且前端頁面可以靈活的操作改數據)>>> 模板語法
ps:模板語法需要依賴第三方模塊。(例如jinja2)
案例一:自制web框架
import socket """ 請求首行 b'GET / HTTP/1.1\r\n 請求頭(一大堆kv鍵值對) Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n \r\n 請求體 ' """ server = socket.socket() # 不傳參數默認就是TCP協議 server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() # 阻塞 等待客戶端鏈接 data = conn.recv(1024) conn.send(b'HTTP/1.1 200 OK\r\n\r\n') print(data) # 手動處理http數據獲取用戶訪問的路徑 current_path = data.decode('utf-8').split('\r\n')[0].split(' ')[1] if current_path == '/index': # 路由匹配上之后返回index # conn.send(b'<h1>index</h1>') with open('index.html','rb') as f: conn.send(f.read()) else: # 當匹配不上的時候統一返回404 conn.send(b'404') conn.close()
案例二:基於wsgiref框架
from wsgiref.simple_server import make_server from urls import * def run(env,response): # env:包含請求信息的dict對象 # response:發送HTTP相應的函數 response('200 OK',[('username','jason'),('password','123')]) # 固定寫法 后面列表里面一個個元祖會以響應頭kv鍵值對的形式返回給客戶端 # 獲取用戶訪問的路徑 current_path = env.get('PATH_INFO') # 定義一個存儲函數名的變量名 func = None # 循環比對路由與試圖函數的映射關系 for url_map in urls: # url_map = ('/index',index) if current_path == url_map[0]: # 匹配成功直接調用函數,並且結束循環 func = url_map[1] break if func: res = func(env) else: # 沒有用戶想要訪問的路徑,則返回一個錯誤信息 res = error(env) # 最后進行編碼處理 return [res.encode('utf-8')] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
urls.py:
from views import * urls = [ ('/index',index), ('/login',login), ('/reg',reg), ('/get_time',get_time), ('/get_user',get_user), ('/get_db',get_db), ]
view.py:
def index(env): return 'index' def login(env): return 'login' def reg(env): return 'reg' def get_time(env): # 先獲取當前時間 current_time = time.strftime('%Y-%m-%d %X') # 打開html文件讀取內容返回給客戶端 with open(r'templates/get_time.html','r',encoding='utf-8') as f: data = f.read() # 因為是以r模式打開的文件,所有獲取到的內容就是一堆字符串 res = data.replace('@@time@@',current_time) # 字符串的替換 return res def get_user(env): with open(r'templates/get_user.html','r',encoding='utf-8') as f: data = f.read() tmp = Template(data) # 將字典傳遞給前端頁面 前端通過變量名user_dic就可以獲取到該字典 return tmp.render(user_dic={'name':"jason",'password':'123'}) def get_db(env): # 連接數據庫 獲取數據 渲染到前端頁面 conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', password = '123', database = 'day54', charset = 'utf8', autocommit = True ) cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.execute('select * from userinfo') user_dict= cursor.fetchall() # [{},{},{},{}] with open(r'templates/get_db.html','r',encoding='utf-8') as f: data = f.read() tmp = Template(data) return tmp.render(user_dict=user_dict) def error(env): return '404 error'
get_time.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> @@time@@ </body> </html>
get_user.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <!--jinja2支持的格式--> <p>{{ user_dic }}</p> <p>{{ user_dic.name }}</p> <p>{{ user_dic['password'] }}</p> <p>{{ user_dic.get('name') }}</p> </body> </html>
get_db.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <table class="table table-hover table-striped table-bordered"> <thead> <tr> <th>id</th> <th>name</th> <th>password</th> </tr> </thead> <tbody> <!--jinja2的for循環開始--> {% for user in user_dict %} <!--[{},{},{},{}]--> <tr> <td>{{ user.id }}</td> <td>{{ user.name }}</td> <td>{{ user.password }}</td> </tr> {% endfor %} <!--jinja2的for循環結束--> </tbody> </table> </div> </div> </div> {{ user_dict }} <!--[{},{},{},{}]--> </body> </html>