Web應用程序是一種能夠經過web訪問的應用程序(web應用本質是基於socket實現的應用程序),程序的最大好處是用戶很容易訪問應用程序,用戶只須要有瀏覽器便可,不須要再安裝其餘軟件。應用程序有兩種模式C/S、B/S。C/S是客戶端/服務器端程序,也就是說這類程序通常獨立運行。而B/S就是瀏覽器端/服務器端應用程序,這類應用程序通常藉助谷歌,火狐等瀏覽器來運行。WEB應用程序通常是B/S模式。Web應用程序首先是「應用程序」,和用標準的程序語言,如java,python等編寫出來的程序沒有什麼本質上的不一樣。在網絡編程的意義下,瀏覽器是一個socket客戶端,服務器是一個socket服務端。html
以下代碼是一個python寫的服務端代碼,能夠用瀏覽器當客戶端去訪問該服務端,理解web服務:java
import socket def handle_request(conn): request_data = conn.recv(1024) print("request_data: ", request_data) # 觀察並分析request_data值 conn.send("HTTP/1.1 200 OK\r\nstatus: 200\r\nContent-Type:text/html\r\n\r\n<h1>Hello, World!</h1>".encode("utf8")) # 響應首行 \r\n響應頭(能夠有多個鍵值對,以\r\n分隔) \r\n\r\n響應體 def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 8812)) sock.listen(5) while True: print("the server is waiting for client-connection....") conn, addr = sock.accept() handle_request(conn) conn.close() if __name__ == '__main__': main()
HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用於萬維網(WWW:World Wide Web)服務器與本地瀏覽器之間傳輸超文本的傳送協議。python
HTTP是一個屬於應用層的面向對象的協議,因爲其簡捷、快速的方式,適用於分佈式超媒體信息系統。它於1990年提出,通過幾年的使用與發展,獲得不斷地完善和擴展。HTTP協議工做於客戶端-服務端架構上。瀏覽器做爲HTTP客戶端經過URL向HTTP服務端即WEB服務器發送全部請求。Web服務器根據接收到的請求,向客戶端發送響應信息。mysql
(1)基於TCP/IP web
HTTP協議是基於TCP/IP協議之上的應用層協議。sql
(2)基於請求-響應模式shell
HTTP協議規定,請求從客戶端發出,最後服務器端響應該請求並返回。換句話說,確定是先從客戶端開始創建通訊的,服務器端在沒有接收到請求以前不會發送響應。數據庫
(3)無狀態保存django
HTTP是一種不保存狀態,即無狀態(stateless)協議。HTTP協議自身不對請求和響應之間的通訊狀態進行保存。也就是說在HTTP這個級別,協議對於發送過的請求或響應都不作持久化處理。編程
使用HTTP協議,每當有新的請求發送時,就會有對應的新響應產生。協議自己並不保留以前一切的請求或響應報文的信息。這是爲了更快地處理大量事務,確保協議的可伸縮性,而特地把HTTP協議設計成如此簡單的。但是,隨着Web的不斷髮展,因無狀態而致使業務處理變得棘手的狀況增多了。好比,用戶登陸到一家購物網站,即便他跳轉到該站的其餘頁面後,也須要能繼續保持登陸狀態。針對這個實例,網站爲了可以掌握是誰送出的請求,須要保存用戶的狀態。HTTP/1.1雖然是無狀態協議,但爲了實現指望的保持狀態功能,因而引入了Cookie技術。有了Cookie再用HTTP協議通訊,就能夠管理狀態了。有關Cookie的詳細內容稍後講解。
(4)無鏈接
無鏈接的含義是限制每次鏈接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接。採用這種方式能夠節省傳輸時間。
http協議包含由瀏覽器發送數據到服務器須要遵循的請求協議與服務器發送數據到瀏覽器須要遵循的響應協議。用於HTTP協議交互的信被爲HTTP報文。請求端(客戶端)的HTTP報文作請求報文,響應端(服務器端)的作響應報文。HTTP報文自己是由多行數據構成的字符串文本。
(1)請求協議
請求格式,如圖:
請求方式:get與post
a、GET提交的數據會放在URL中的路徑以後,以?分割路徑和傳輸數據,參數之間以&相連,如EditBook?name=test&pwd=123;POST方法是把提交的數據放在HTTP包的請求體中;
b、GET提交的數據大小有限制(由於瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制(即POST方法纔有請求體);
c、GET與POST請求在服務端獲取請求數據方式不一樣;
示例:GET / HTTP/1.1\r\n Host: 127.0.0.1:8812\r\nUser-Agent: Mozilla/5.0...\r\n\r\n
(2)響應協議
響應格式,如圖:
示例:HTTP/1.1 200 OK\r\nstatus:200\r\nContent-Type:text/html\r\n\r\n<h1>Hello</h1>
響應狀態碼:狀態碼的職責是當客戶端向服務器端發送請求時, 描述返回的請求結果。藉助狀態碼,用戶能夠知道服務器端是正常處理了請求,仍是出現了錯誤。狀態碼(如:200 OK)以3位數字和緣由短語組成。數字中的第一位指定了響應類別,後兩位無分類。響應類別有如下5種:
演示實例:
import socket sock = socket.socket() sock.bind(("127.0.0.1",8808)) sock.listen(5) while 1: print("server waiting.....") conn,addr = sock.accept() data = conn.recv(1024) print("request-data",data) # 讀取html文件 with open("login.html","rb") as f: data = f.read() conn.send((b"HTTP/1.1 200 OK\r\n\r\n%s"%data)) conn.close()
login.html文件:
<!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框架就是在以上十幾行代碼基礎上擴展出來的,有不少簡單方便使用的方法,大大提升了開發的效率。
最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。
若是要動態生成HTML,就須要把上述步驟本身來實現。不過,接收HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,若是咱們本身來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。
正確的作法是底層代碼由專門的服務器軟件實現,咱們用Python專一於生成HTML文檔。由於咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口協議來實現這樣的服務器軟件,讓咱們專心用Python編寫Web業務。這個接口就是WSGI:Web Server Gateway Interface。而wsgiref模塊就是python基於wsgi協議開發的服務模塊。
閱讀以下代碼,理解wsgiref模塊用法:
from wsgiref.simple_server import make_server def application(environ, start_response): """ environ:wsgiref 模塊幫咱們封裝好的請求信息字典 start_response:用來封裝響應格式 """ print(environ) start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求,內部封裝好了socket,等待客戶端來鏈接,當有請求進來的時候執行application函數: httpd.serve_forever()
總結:wsgiref模塊的主要做用是拆請求協議的包和封裝響應格式。
目錄結構以下:
import pymysql conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',password='',db='mydb') 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()
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("",8080,applications) print("Serving HTTP on port 8080...") server.serve_forever()
from app01.views import * URLpattern = ( ("/login/", login), )
import pymysql from urllib.parse import parse_qs def login(environ): if environ.get("REQUEST_METHOD") == "POST": try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 request_body = environ['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',password='',db='mydb') # 建立遊標 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
<!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>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>welcome to myweb!</h4> </body> </html>
myweb這個package就是一個web框架,下載這個web框架就能夠快速實現一些簡單的web功能,好比查看時間。
a、MVC
Web服務器開發領域裏著名的MVC模式,所謂MVC就是把Web應用分爲模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的、鬆耦合的方式鏈接在一塊兒,模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互(頁面),控制器接受用戶的輸入調用模型和視圖完成用戶的請求,其示意圖以下所示:
b、MTV
Django的MTV模式本質上和MVC是同樣的,也是爲了各組件間保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別是指:
M 表明模型(Model): 負責業務對象和數據庫的關係映射(ORM)。
T 表明模板 (Template):負責如何把頁面展現給用戶(html)。
V 表明視圖(View): 負責業務邏輯,並在適當時候調用Model和Template。
除了以上三層以外,還須要一個URL分發器,它的做用是將一個個URL的頁面請求分發給不一樣的View處理,View再調用相應的Model和Template,MTV的響應模式以下所示:
通常是用戶經過瀏覽器向咱們的服務器發起一個請求(request),這個請求會去訪問視圖函數,(若是不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去數據庫查找數據,而後逐級返回,視圖函數把返回的數據填充到模板中空格中,最後返回網頁給用戶。
(1)下載Django
pip3 install django # 不寫版本號,默認下載最新版本
pip3 install django==2.1.2 # 指定版本
(2)建立一個django project(django-admin.exe所在目錄要加入環境變量)
django-admin startproject mysite
注意:此命令在哪一個目錄下執行,django項目就建在了哪一個目錄下
執行後,當前目錄會生成mysite的工程,目錄結構以下:
manage.py -- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。
settings.py -- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
urls.py -- 負責把URL模式映射到應用程序。
(3)在mysite目錄下建立應用(必定要先進入manage.py所在目錄,再執行以下命令)
python manage.py startapp blog
注意:一個項目中有多個應用,每一個應用都有本身的業務邏輯
執行後,mysite目錄下會生成blog這個應用,目錄以下:
(4)啓動django項目(不寫端口,默認是8000)
python manage.py runserver 8080
這樣咱們的django就啓動起來了!當咱們訪問:http://127.0.0.1:8080/時就能夠看到:
urls文件(url控制器):
from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path(r'^admin/$', admin.site.urls), path(r'^index/$', views.index), }
views文件(視圖):
from django.shortcuts import render # Create your views here. import datetime def index(request): now = datetime.datetime.now() ctime = now.strftime("%Y-%m-%d %X") return render(request,"index.html",{"ctime":ctime})
index.html(模板文件)- 若沒有templates目錄則手動建立,其中放html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>當前時間:{{ ctime }}</h4> </body> </html>
經過瀏覽器訪問127.0.0.1:8080/index/,查看效果。
注意:每個視圖函數都傳一個request形參,封裝了請求協議,並返回HttpResponse對象。
協議://域名:端口號/路徑?參數(鍵值對,如:user=name&pwd=123)
示例:https://www.baidu.com:80/s?wd=alex
用命令建立完成後沒有templates文件夾(存放html文件),須要手動建立,而且有些版本沒有配置templates路徑,需手動配置,方法以下:
找到settings.py文件中的TEMPLATES列表中的 'DIRS': [os.path.join(BASE_DIR, "templates")]
當使用django時,若是頁面遇到forbidden錯誤時(post提交容易發生),就去settings.py文件中找到MIDDLEWARE列表的第3項'django.middleware.csrf.CsrfViewMiddleware',將其註釋掉便可。