Web應用程序是一種能夠經過Web訪問的應用程序,程序的最大好處是用戶很容易訪問應用程序,用戶只須要有瀏覽器便可,不須要再安裝其餘軟件。
應用程序有兩種模式C/S、B/S。C/S是客戶端/服務器端程序,也就是說這類程序通常獨立運行。而B/S就是瀏覽器端/服務器端應用程序,
這類應用程序通常藉助谷歌,火狐等瀏覽器來運行。WEB應用程序通常是B/S模式。Web應用程序首先是「應用程序」,和用標準的程序語言,
如java,python等編寫出來的程序沒有什麼本質上的不一樣。在網絡編程的意義下,瀏覽器是一個socket客戶端,服務器是一個socket服務端html
import socket def handle_request(client): request_data = client.recv(1024) print("request_data: ",request_data) client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8")) client.send("<h1 style='color:red'>Hello, 路飛學城! </h1>".encode("utf8")) def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8800)) sock.listen(5) while True: print("the server is waiting for client-connection....") connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main()
1.簡介
HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用於萬維網(WWW:World Wide Web )服務器與本地瀏覽器之間傳輸超文本的傳送協議。
HTTP是一個屬於應用層的面向對象的協議,因爲其簡捷、快速的方式,適用於分佈式超媒體信息系統。它於1990年提出,通過幾年的使用與發展,獲得不斷地完善和擴展。
HTTP協議工做於客戶端-服務端架構爲上。瀏覽器做爲HTTP客戶端經過URL向HTTP服務端即WEB服務器發送全部請求。Web服務器根據接收到的請求後,向客戶端發送響應信息。
2.特性
(1) 基於TCP/IP
http協議是基於TCP/IP協議之上的應用層協議。
(2) 基於請求-響應模式
HTTP協議規定,請求從客戶端發出,最後服務器端響應該請求並返回。換句話說,確定是先從客戶端開始創建通訊的,服務器端在沒有 接收到請求以前不會發送響應。
(3) 無狀態保存
HTTP是一種不保存狀態,即無狀態(stateless)協議。HTTP協議 自身不對請求和響應之間的通訊狀態進行保存。
也就是說在HTTP這個 級別,協議對於發送過的請求或響應都不作持久化處理。
使用HTTP協議,每當有新的請求發送時,就會有對應的新響應產生。協議自己並不保留以前一切的請求或響應報文的信息。
這是爲了更快地處理大量事務,確保協議的可伸縮性,而特地把HTTP協議設計成如此簡單的。
但是,隨着Web的不斷髮展,因無狀態而致使業務處理變得棘手的狀況增多了。好比,用戶登陸到一家購物網站,即便他跳轉到該站的其餘頁面後,
也須要能繼續保持登陸狀態。針對這個實例,網站爲了可以掌握是誰送出的請求,須要保存用戶的狀態。
HTTP/1.1雖然是無狀態協議,但爲了實現指望的保持狀態功能, 因而引入了Cookie技術。有了Cookie再用HTTP協議通訊,就能夠管理狀態了。
有關Cookie的詳細內容以後講解。
(4)無鏈接
無鏈接的含義是限制每次鏈接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接。採用這種方式能夠節省傳輸時間。
3.http請求協議與響應協議
http協議包含由瀏覽器發送數據到服務器須要遵循的請求協議與服務器發送數據到瀏覽器須要遵循的響應協議。
用於HTTP協議交互的信被爲HTTP報文。請求端(客戶端)的HTTP報文 作請求報文,響應端(服務器端)的 作響應報文。
HTTP報文自己是由多行數據構成的文本。
請求協議
請求格式:
請求方式: get與post請求
GET提交的數據會放在URL以後,以?分割URL和傳輸數據,參數之間以&相連,如EditBook?name=test1&id=123456。POST方法是把提交的數據放在HTTP包的請求體中.
GET提交的數據大小有限制(由於瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
GET與POST請求在服務端獲取請求數據方式不一樣。
響應協議
響應格式:
響應狀態碼
狀態碼的是當客戶端向服務器端發送請求時, 返回的請求結果。藉助狀態碼,用戶能夠知道服務器端是正常處理了請求,仍是出現了問題 。
狀態碼如200 OK,以3位數字和緣由組成。數字中的 一位指定了響應類別,後兩位無分。響應分爲別5種。
4.示例
url: 默認端口 80
協議 ip 端口/路徑?a=1
https://www.jd.com/
請求協議:
請求首行\r\n
請求頭\r\n
請求頭\r\n
請求頭\r\n
...
/r/n/r/n
請求體(a=1&b=2) # 注意:只有post請求才有請求體
請求方式: get與post請求
GET提交的數據會放在URL以後,以?分割URL和傳輸數據,參數之間以&相連,如EditBook?name=test1&id=123456.
POST方法是把提交的數據放在HTTP包的請求體中.
GET提交的數據大小有限制(由於瀏覽器對URL的長度有限制),
而POST方法提交的數據沒有限制.
GET與POST請求在服務端獲取請求數據方式不一樣。
何時發get 何時發post
查詢時 用get
作數據庫更新操做用post
b'GET / HTTP/1.1 \r\nHost: 127.0.0.1:8080 \r\nConnection: keep-alive \r\nCache-Control: max-age=0 \r\nUpgrade-Insecure-Requests: 1 \r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 \r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 \r\nAccept-Encoding: gzip, deflate, br \r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8 \r\n\r\n' b'GET /yuan?name=yuan&age=22 HTTP/1.1 \r\nHost: 127.0.0.1:8080 \r\nConnection: keep-alive \r\nUpgrade-Insecure-Requests: 1 \r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 \r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 \r\nAccept-Encoding: gzip, deflate, br \r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8 \r\n\r\n' b'POST / HTTP/1.1 \r\nHost: 127.0.0.1:8080 \r\nConnection: keep-alive\r\nContent-Length: 18 \r\nCache-Control: max-age=0 \r\nOrigin: http://127.0.0.1:8080\r\nUpgrade-Insecure-Requests: 1 \r\nContent-Type: application/x-www-form-urlencoded \r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 \r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 \r\nReferer: http://127.0.0.1:8080 \r\nAccept-Encoding: gzip, deflate, br \r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8 \r\n\r\n user=alice&pwd=123' #只有post請求才有請求體
import socket sock = socket.socket() sock.bind(('127.0.0.1',8080)) sock.listen(5) while True: print('server waiting ...') conn,addr = sock.accept() data = conn.recv(1024) print('data:',data) # 讀取html 文件 with open('login.html','rb') as f: data = f.read() # conn.send(b'HTTP/1.1 200 OK\r\n\r\nhello luffy') # conn.send(b'HTTP/1.1 200 OK\r\n\r\n%s'%data) conn.send(b'HTTP/1.1 200 OK\r\nContent-Type:text/html\r\n\r\n%s'%data) conn.close()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> 用戶名 <input type="text" name="user"> 密碼 <input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
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 login(environ): with open('login.html','rb') as f: data = f.read() return data def reg(environ): with open('reg.html','rb') as f: data = f.read() return data def index(environ): with open('index.html','rb') as f: data = f.read() return data def fav(environ): with open('favicon.ico','rb') as f: data = f.read() return data url_patterns = [ ('/login', login), ('/reg', reg), ('/index', index), ('/favicon', fav) ] def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print('PATH:',environ.get('PATH_INFO')) # path 當前請求路徑 path = environ.get('PATH_INFO') func = None for item in url_patterns: if path == item[0]: func = item[1] break if func: return [func(environ)] else: return [b'404'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()
QIY一個web框架
models.pyjava
import pymysql #鏈接數據庫 conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',passwd='',db='web') #db:庫名 #建立遊標 cur = conn.cursor() sql=''' create table userinfo( id INT PRIMARY KEY , name VARCHAR(32) , password VARCHAR(32) ) ''' cur.execute(sql) #提交 conn.commit() #關閉指針對象 cur.close() #關閉鏈接對象 conn.close()
啓動文件manage.pypython
from wsgiref.simple_server import make_server from app01.views import * import urls def routers(): URLpattern=urls.URLpattern return URLpattern def applications(environ,start_response): path=environ.get("PATH_INFO") start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')]) urlpattern=routers() func=None for item in urlpattern: if path==item[0]: func=item[1] break if func: return [func(environ)] else: return [b"<h1>404!<h1>"] if __name__ == '__main__': server=make_server("",8889,applications) print("server is working...") server.serve_forever()
urls.pymysql
from app01.views import * URLpattern = ( ("/login/", login), )
viewsweb
import pymysql from urllib.parse import parse_qs def login(request): if request.get("REQUEST_METHOD")=="POST": try: request_body_size = int(request.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 request_body = request['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") #鏈接數據庫 conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',passwd='',db='web') # db:庫名 #建立遊標 cur = conn.cursor() SQL="select * from userinfo WHERE NAME ='%s' AND PASSWORD ='%s'"%(user,pwd) cur.execute(SQL) if cur.fetchone(): f=open("templates/backend.html","rb") data=f.read() data=data.decode("utf8") return data.encode("utf8") else: print("OK456") return b"user or pwd is wrong" else: f = open("templates/login.html", "rb") data = f.read() f.close() return data
login.htmlsql
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>登陸頁面</h4> <form action="" method="post"> 用戶名 <input type="text" name="user"> 密碼 <input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
backend.html數據庫
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>welcome to oldboy!</h4> </body> </html>
yuan這個package就是一個web框架,下載這個web框架就能夠快速實現一些簡單的web功能,好比查看時間。django
http://www.cnblogs.com/yuanchenqi/articles/8869302.html
http://www.cnblogs.com/yuanchenqi/articles/8875623.html
http://www.cnblogs.com/yuanchenqi/articles/8946917.html
1. web框架的原理(實質)
1. 理解!!!
博客園(socket server)
0.先啓動服務,監聽
while 1:
等待鏈接...
3. 接收到你的請求
4. 根據你的需求,返回相應的內容
斷開
你的瀏覽器(socket client)
1. 請求鏈接服務端(IP和端口)
2. 發送消息(我想要xx)
5. 收到返回的消息
斷開
HTTP協議補充:
1. 請求(request)和響應(response)
2. HTTP請求的生命週期
1. Web框架本質
本質上:socket互發消息
2. 不一樣的URL返回不一樣的內容
本質上:根據路徑的不一樣返回不一樣的內容
3. 動態的網頁
本質上:字符串的替換
小總結:
A. socket server URL路徑 --> 服務器程序(專門用來處理socket收發消息部分)
B. 根據不一樣的URL路徑執行不一樣的函數 路徑-->函數 --> 應用程序(業務邏輯,控制要返回的消息的具體內容)
C. 具體返回內容 動態的網頁 字符串的替換 --> jinja2
經常使用的服務器程序: wsgi協議:定義了 服務器程序和Django/Flask通訊的規範!
1. wsgiref Python內置的模塊
2. Gunicorn和uwsgi
大總結:
Python Web框架分類:
1. 第三方的A, 本身寫B和C --> Django
2. 第三方的A和C 本身寫自帶B --> Flask
3. 本身寫A、B、C --> Tornado
另一個層面的分類:
1. Django 大而全(基本上作網站用到的它本身都有) 缺點就是臃腫
2. 其餘 Flask小而美
2. Django(第一個Django實例)
1. 安裝
1. pip install django==1.11.11
2. 卸載:pip uninstall django
官網:www.djangoproject.com
https://www.djangoproject.com/download/
// pip -v # 查看pip 是爲python2 仍是python3
// pip list # 查看全部安裝得第三方
http://www.cnblogs.com/liwenzhou/p/8258992.html
2. 建立Django項目
1. 命令行建立
1. 切換到你要保存Django項目的目錄下
2. 執行:django-admin startproject 項目名
2. PyCharm建立
3. 啓動Django項目
1. 命令行:python manage.py runserver IP:端口
2. PyCharm 點綠色的小三角
4. Django項目的設置
1. 註釋csrf
2. 配置templates文件夾的路徑
3. 配置static 文件夾的路徑
3. 做業
1. 用Django把你以前寫的登陸頁面返回!
http://www.cnblogs.com/liwenzhou/p/8258992.html
http://www.cnblogs.com/liwenzhou/articles/8620663.html
1. 內容回顧
1. 本身寫一個web框架
2. 補充HTTP協議
1. 請求(request)
2. 響應(response)
消息的格式:
見圖
見Blog:http://www.cnblogs.com/liwenzhou/articles/8620663.html
3. wsgiref模塊
4. jinja2 模板語言
本質上就是 字符串替換(渲染render)
2.Django
1. Django安裝
pip install django==1.11.11
2. 新建Django項目
1. 命令行建立
1. django-admin startproject mysite (會在當前目錄下新建Django項目)
2. PyCharm建立
1. File -> new project --> Django --> 填路徑選Python解釋器
3. Django項目配置
1.
2.
3.
4. 啓動Django
/
3. 今日內容
1. 登陸示例完善版
1. 頁面日後端提交數據要使用form表單!!!不是from!!!
form表單提交數據注意事項:(週一默寫!!!)
1. 提交按鈕要使用submit!!!
2. input要寫在form表單裏面,input標籤要有name屬性
3. form標籤要加action和method,若是有文件的話還要加一個enctype這個屬性
2. PyCharm啓動Django項目
1. 注意小三角左邊的項目名要和項目名一致才能啓動Django項目
3.
2. app概念
1. 什麼是app,一個大的Django項目內部能夠分紅不少個APP
2. 建立APP
1. 命令行 python manage.py startapp app01
2. PyCharm建立
3. models.py 數據庫
1. 類 ---> 表
2. 對象 ---> 數據行
3. 屬性 ---> 字段
兩個神奇的命令:(注意順序)
1. python manage.py makemigrations
2. python manage.py migrate
Django默認用的數據庫:
sqlite3 --> 文件數據庫
下週咱們來學習怎麼鏈接MySQL
查詢數據庫的語法:
1. 取出全部的數據
類名.objects.all() 返回全部的對象
類名.objects.filter(id=1) 返回的是對象的一個列表
類名.objects.get(id=1) 返回的是單獨的對象。可是當id不存在時會報錯,
模板語言的語法: --> render(request, "xx.html", {"data": data})
1. {{ name }}
2. {% for i in xx %}
{{i.xx}}
{% endfor %}
4.做業
1. 本身在models.py中寫一個class類
2. 建立一些測試數據
3. 在頁面(使用咱們以前上課寫得Bootstrap的後臺管理頁面)上展現出來
wsgiref 編程
# -*- coding:utf-8 -*- ''' http://www.cnblogs.com/liwenzhou/p/8258992.html wsgiref ''' import time from wsgiref.simple_server import make_server def index(url): with open('index.html','r',encoding='utf-8') as f: s = f.read() s = s.replace('oo',str(time.time())) return bytes(s,encoding='utf-8') def home(url): with open('home.html','r',encoding='utf-8') as f: s = f.read() return bytes(s, encoding='utf-8') # 定義一個url 和實際要執行得函數得對應關係 list1 = [ ('/index',index), ('/home',home) ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息 url = environ['PATH_INFO'] # 取到用戶輸入的url print(url) func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8080, run_server) print("我在8080等你哦...") httpd.serve_forever()
wsgiref-jinja2後端
# -*- coding:utf-8 -*- ''' http://www.cnblogs.com/liwenzhou/p/8258992.html wsgiref jinja2 pip install jinja2 CREATE TABLE user( id int auto_increment PRIMARY KEY, name CHAR(10) NOT NULL, hobby CHAR(20) NOT NULL )engine=innodb DEFAULT charset=UTF8; ''' import time from wsgiref.simple_server import make_server import jinja2 def index(url): with open('index.html','r',encoding='utf-8') as f: s = f.read() s = s.replace('oo',str(time.time())) return bytes(s,encoding='utf-8') def home(url): with open('home.html','r',encoding='utf-8') as f: s = f.read() return bytes(s, encoding='utf-8') def alice(url): with open('alice.html', 'r', encoding='utf-8') as f: s = f.read() template = jinja2.Template(s) # 生成模板對象 data = {'name':'alice','hobby_list':['學習','運動','讀書']} response = template.render(data) # 本質上 完成了字符串得 替換 return bytes(response,encoding='utf-8') # 定義一個url 和實際要執行得函數得對應關係 list1 = [ ('/index',index), ('/home',home), ('/alice',alice) ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息 url = environ['PATH_INFO'] # 取到用戶輸入的url print(url) func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8080, run_server) print("我在8080等你哦...") httpd.serve_forever()
wsgiref-jinja2-pymysql
# -*- coding:utf-8 -*- ''' http://www.cnblogs.com/liwenzhou/p/8258992.html wsgiref jinja2 pymysql pip install jinja2 CREATE TABLE user( id int auto_increment PRIMARY KEY, name CHAR(10) NOT NULL, hobby CHAR(20) NOT NULL )engine=innodb DEFAULT charset=UTF8; ''' import time from wsgiref.simple_server import make_server import jinja2 import pymysql def index(url): with open('index.html','r',encoding='utf-8') as f: s = f.read() s = s.replace('oo',str(time.time())) return bytes(s,encoding='utf-8') def home(url): with open('home.html','r',encoding='utf-8') as f: s = f.read() return bytes(s, encoding='utf-8') def alice(url): with open('alice.html', 'r', encoding='utf-8') as f: s = f.read() template = jinja2.Template(s) # 生成模板對象 # data = {'name':'alice','hobby_list':['學習','運動','讀書']} conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="123", db="userinfo", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select name, hobby from user") user = cursor.fetchone() # user_list = cursor.fetchall() cursor.close() conn.close() print('user:',user) print('*'*120) hobby_list = user['hobby'].split() user['hobby_list'] = hobby_list print('user:', user) print('*' * 120) response = template.render(user) # 本質上 完成了字符串得 替換 return bytes(response,encoding='utf-8') # 定義一個url 和實際要執行得函數得對應關係 list1 = [ ('/index',index), ('/home',home), ('/alice',alice) ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設置HTTP響應的狀態碼和頭信息 url = environ['PATH_INFO'] # 取到用戶輸入的url print(url) func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8080, run_server) print("我在8080等你哦...") httpd.serve_forever()
alice.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>alice</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>愛好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h1>這是index頁面</h1> <h2>oo</h2> </body> </html>