一、web簡單框架的構建


一、HTTP協議

http協議簡介

超文本傳輸協議(英文:HyperText Transfer Protocol,縮寫:HTTP) 是一種用於分布式、協作式和超媒體信息系統的應用層協議。 

1999年6月公布的 RFC 2616,定義了HTTP協議中現今廣泛使用的一個版本——HTTP 1.1。 

http協議概述

HTTP是一個客戶端終端(用戶)和服務器端(網站)請求和應答的標准(TCP) 

通常,由HTTP客戶端發起一個請求,創建一個到服務器指定端口(默認是80端口)的TCP連接。HTTP服務器則在那個端口監聽客戶端的請求。一旦收到請求,服務器會向客戶端返回一個狀態,比如"HTTP/1.1 200 OK",以及返回的內容,如請求的文件、錯誤消息、或者其它信息。 

HTTP工作原理

HTTP 請求/響應的步驟:

  1. 客戶端連接到web服務器
    一個HTTP客戶端,通常是瀏覽器,與Web服務器的HTTP端口(默認為80)建立一個TCP套接字連接。例如,http://www.luffycity.com
  2. 發送HTTP請求
    通過TCP套接字,客戶端向Web服務器發送一個文本的請求報文,一個請求報文由請求行、請求頭部、空行和請求數據4部分組成。
  3. 服務器接受請求並返回HTTP響應
    Web服務器解析請求,定位請求資源。服務器將資源復本寫到TCP套接字,由客戶端讀取。一個響應由狀態行、響應頭部、空行和響應數據4部分組成。
  4. 釋放連接TCP連接
    若connection 模式為close,則服務器主動關閉TCP連接,客戶端被動關閉連接,釋放TCP連接;若connection 模式為keepalive,則該連接會保持一段時間,在該時間內可以繼續接收請求;
  5. 客戶端瀏覽器解析HTML內容
    客戶端瀏覽器首先解析狀態行,查看表明請求是否成功的狀態代碼。然后解析每一個響應頭,響應頭告知以下為若干字節的HTML文檔和文檔的字符集。客戶端瀏覽器讀取響應數據HTML,根據HTML的語法對其進行格式化,並在瀏覽器窗口中顯示。

HTTP請求方法

請求方法
	get post
	GET提交的數據會放在URL之后,也就是請求行里面,以?分割URL和傳輸數據,參數之間以&相連,如EditBook?name=test1&id=123456.(請求頭里面那個content-type做的這種參數形式,后面講) POST方法是把提交的數據放在HTTP包的請求數據部分中.
    GET提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
    GET與POST請求在服務端獲取請求數據方式不同,就是我們自己在服務端取請求數據的時候的方式不同了

	常用的get請求方式:瀏覽器輸入網址  ,a標簽 ,form標簽 method='get'
	post請求方法,一般都用來提交數據.比如用戶名密碼登錄	

	其他方法:HEAD PUT DELETE TRACE OPTIONS CONNECT PATCH請求方法
	get post
    GET提交的數據會放在URL之后,也就是請求行里面,以?分割URL和傳輸數據,參數之間以&相連,如EditBook?name=test1&id=123456.(請求頭里面那個content-type做的這種參數形式,后面講) POST方法是把提交的數據放在HTTP包的請求數據部分中.
    GET提交的數據大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數據沒有限制.
    GET與POST請求在服務端獲取請求數據方式不同,就是我們自己在服務端取請求數據的時候的方式不同了

	常用的get請求方式:瀏覽器輸入網址  ,a標簽 ,form標簽 method='get'
	post請求方法,一般都用來提交數據.比如用戶名密碼登錄	

	其他方法:HEAD PUT DELETE TRACE OPTIONS CONNECT PATCH
	GET:就是獲取數據的操作
	DELETE:就是請求服務器刪除數據的操作
	POST:就是添加數據的操作
	PUT:就是更新數據的操作
	....
  • get請求和post的區別

    <form action="http://127.0.0.1:8001">
        用戶名:<input type="text" name="username">
        密  碼: <input type="text" name="password">
        <input type="submit">
    </form>
    
    GET /?username=alex&password=123 HTTP/1.1  提交的數據會放在URL之后,也就是請求行里面
    Host: 127.0.0.1:8001
    Connection: keep-alive
    .....
    
    <form action="http://127.0.0.1:8001" method="post">
        用戶名:<input type="text" name="username">
        密  碼: <input type="text" name="password">
        <input type="submit">
    </form>
    
    POST / HTTP/1.1
    Host: 127.0.0.1:8001
    Connection: keep-alive
    ....
    
    username=alex&password=dasd  POST方法是把提交的數據放在HTTP包的請求數據部分中
    

    get:

    post:

HTTP狀態碼

狀態代碼的第一個數字代表當前響應的類型:

  • 1xx消息——請求已被服務器接收,繼續處理
  • 2xx成功——請求已成功被服務器接收、理解、並接受
  • 3xx重定向——需要后續操作才能完成這一請求
  • 4xx請求錯誤——請求含有詞法錯誤或者無法被執行
  • 5xx服務器錯誤——服務器在處理某個正確請求時發生錯誤

URL

超文本傳輸協議(HTTP)的統一資源定位符將從因特網獲取信息的五個基本元素包括在一個簡單的地址中:

  • 傳送協議。
  • 層級URL標記符號(為[//],固定不變)
  • 訪問資源需要的憑證信息(可省略)
  • 服務器。(通常為域名,有時為IP地址)
  • 端口號。(以數字方式表示,若為HTTP的默認值“:80”可省略)
  • 路徑。(以“/”字符區別路徑中的每一個目錄名稱)
  • 查詢。(GET模式的窗體參數,以“?”字符為起點,每個參數以“&”隔開,再以“=”分開參數名稱與數據,通常以UTF8的URL編碼,避開字符沖突的問題)
  • 片段。以“#”字符為起點

比如:https://www.cnblogs.com/clschao/articles/9230431.html?name=chao&age=18

HTTP請求協議格式

請求格式
    GET / HTTP/1.1  ---  GET /clschao/articles/9230431.html?name=chao&age=18 HTTP/1.1
    User-Agent:....
    xx:xx

    請求數據  get請求方法沒有請求數據  post請求數據方法的請求數據放在這里

HTTP響應響應協議格式

響應格式
    HTTP/1.1 200 ok
    kl:v1
    k2:v2

    響應數據

http協議特點

1.基於  請求-響應 的模式
2.無狀態保存(缺點:每次訪問都是新的,無法維持長時間的聯系,無法和網頁持續的交流)
3.無連接(一次請求一次響應,就斷開連接了,保證效率)

請求:request
響應:response

網頁查看請求和響應的信息

反爬

在請求頭部信息中,有一項User-Agent選項,可以運用與反扒

  • 先寫一個爬取網頁的代碼,爬京東的主頁
    import requests

    res = requests.get('https://www.jd.com/2019')
    
    with open('jd.html','w',encoding='utf-8') as f:
        f.write(res.text)
    ![](https://img2018.cnblogs.com/blog/1673937/201907/1673937-20190718201416470-804501892.png)
    

    訪問的地址是我們本地的地址,
    拿到的的京東的html是可以打開訪問的,跟京東的主頁一樣;就沒有做UA反爬

  • 爬抽屜的主頁
    import requests

    res = requests.get('https://dig.chouti.com/')
    
    with open('ct.html','w',encoding='utf-8') as f:
        f.write(res.text)
    

此時拿到的html頁面打開是顯示網站防火牆的,說明做了UA反爬措施

  • 偽裝來解決反爬的問題
    在抽屜的network中,找到User-Agent,

    以鍵值對的形式放在requests中,讓其以網頁的身份去訪問
    import requests

    res = requests.get('https://dig.chouti.com/',headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'})
    
    with open('ct.html','w',encoding='utf-8') as f:
        f.write(res.text)
    

二、web框架的本質及定義

所有的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端,基於請求做出響應,客戶都先請求,服務端做出對應的響應,按照http協議的請求協議發送請求,服務端按照http協議的響應協議來響應請求,這樣的網絡通信,我們就可以自己實現Web框架了。 

因為socket就是做網絡通信用的,下面我們就基於socket來自己實現一個web框架,寫一個web服務端,讓瀏覽器來請求,並通過自己的服務端把頁面返回給瀏覽器,瀏覽器渲染出我們想要的效果。
  1. 初級版本

    import socket

    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()

    while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    print(from_client_msg)

     conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    
     with open('01momo.html','rb') as f:
         data = f.read()
     conn.send(data)
    
     conn.close()
    

    01momo.html文件中寫着:

    &amp;amp;amp;lt;h1&amp;amp;amp;gt;你好世界&amp;amp;amp;lt;/h1&amp;amp;amp;gt;

    Python中的socket就是服務端,當網頁客戶端來訪問時,就返回給一個html,樣式是一個標題寫着:你好世界

    實現:因為http協議的格式,先寫狀態碼,發送給網頁,然后讀出html文件,發送給客戶端,就實現了一個基本的web框架

  2. 初級版本

    import socket

    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()

    while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    print(from_client_msg)

     conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    
     with open('03簡單版.html','rb') as f:
         data = f.read()
     conn.send(data)
    
     conn.close()
    

    03簡單版.html:

    &amp;amp;amp;lt;head&amp;amp;amp;gt;&amp;amp;amp;lt;br&amp;amp;amp;gt; &amp;amp;amp;lt;style&amp;amp;amp;gt;&amp;amp;amp;lt;br&amp;amp;amp;gt; h1{&amp;amp;amp;lt;br&amp;amp;amp;gt; background-color: yellow;&amp;amp;amp;lt;br&amp;amp;amp;gt; }&amp;amp;amp;lt;br&amp;amp;amp;gt; &amp;amp;amp;lt;/style&amp;amp;amp;gt;&amp;amp;amp;lt;/p&amp;amp;amp;gt; &amp;amp;amp;lt;/head&amp;amp;amp;gt; &amp;amp;amp;lt;body&amp;amp;amp;gt; &amp;amp;amp;lt;h1&amp;amp;amp;gt;你想知道的我們都有&amp;amp;amp;lt;/h1&amp;amp;amp;gt; 一年的四季: &amp;amp;amp;lt;ul&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;春&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;夏&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;秋&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;冬&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;/ul&amp;amp;amp;gt; &amp;amp;amp;lt;/body&amp;amp;amp;gt;

    這個版本在html文件中,寫了css樣式,用同樣的方式,也完成了簡單的web框架,等到了網頁效果

  3. 升級版本

    這個版本考慮到css樣式不是寫在html文件里面,而是單獨寫在一個css文件里,然后用link引入的

    import socket

    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()

    while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    print(from_client_msg)

     conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    
     with open('04升級版.html','rb') as f:
         data = f.read()
     conn.send(data)
    
     conn.close()
    

    04升級版.html:

    &amp;amp;amp;lt;head&amp;amp;amp;gt;&amp;amp;amp;lt;br&amp;amp;amp;gt; &amp;amp;amp;lt;link href="text.css" rel="stylesheet"&amp;amp;amp;gt;&amp;amp;amp;lt;/p&amp;amp;amp;gt; &amp;amp;amp;lt;/head&amp;amp;amp;gt; &amp;amp;amp;lt;body&amp;amp;amp;gt; &amp;amp;amp;lt;h1&amp;amp;amp;gt;你想知道的我們都有&amp;amp;amp;lt;/h1&amp;amp;amp;gt; 一年的四季: &amp;amp;amp;lt;ul&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;春&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;夏&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;秋&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;li&amp;amp;amp;gt;冬&amp;amp;amp;lt;/li&amp;amp;amp;gt; &amp;amp;amp;lt;/ul&amp;amp;amp;gt; &amp;amp;amp;lt;/body&amp;amp;amp;gt;

    text.css:

    h1{
    background-color: yellow;
    }

    test.js:

    alert('客觀來玩呀~~');

    可以正常的拿到頁面,但是css、js效果沒有了

打開網頁的network,分析原因:

發現除了最上邊的主請求,還有text.css、test.js、favicon.ico請求,向服務端要這幾個文件;

因為寫了相對路徑,就是還向自己寫的服務器里請求,而寫了絕對路徑的,比如圖片的網址,就會向別的服務器要,就不用自己再傳一個文件過去了

  1. 升級版本(解決css、js、圖片等問題)

首先要得到請求的文件:

conn,addr = server.accept()
from_client_msg = conn.recv(1024).decode('utf-8')
request_str = from_client_msg
path = request_str.split('\r\n')
print(path)

以 split('\r\n') 分割,就把每個請求行、請求頭都分出來了,取第一項,再以空格切分,取第二項,就是我們要得到的請求地址

path = request_str.split('\r\n')[0].split(' ')[1]

通過判斷路徑的名稱,回復對應請求的文件:

import socket

server = socket.socket()
server.bind(('127.0.0.1',8001))
server.listen()

while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    request_str = from_client_msg
    path = request_str.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    if path == '/':
        with open('04升級版.html','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/text.css':
        with open('text.css','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/test.js':
        with open('test.js','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/1.jpg':
        with open('1.jpg','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/22.ico':
        with open('22.ico','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()

這樣我們就等到了有js、css效果的網頁,但是寫的太low

  1. 函數進階版本

    import socket

    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()

    def html(conn):
    with open('04升級版.html', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def css(conn):
    with open('text.css', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def js(conn):
    with open('test.js', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def jpg(conn):
    with open('1.jpg', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def ico(conn):
    with open('22.ico', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    # print(from_client_msg)
    request_str = from_client_msg
    path = request_str.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    if path == '/':
    html(conn)
    elif path == '/text.css':
    css(conn)
    elif path == '/test.js':
    js(conn)
    elif path == '/1.jpg':
    jpg(conn)
    elif path == '/22.ico':
    ico(conn)

把每個請求放在函數里,通過if判斷去掉對應的函數

  1. 高級版

    import socket

    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()

    def html(conn):
    with open('04升級版.html', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def css(conn):
    with open('text.css', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def js(conn):
    with open('test.js', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def jpg(conn):
    with open('1.jpg', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    def ico(conn):
    with open('22.ico', 'rb') as f:
    data = f.read()
    conn.send(data)
    conn.close()

    urlpatterns = [
    ('/',html),
    ('/text.css',css),
    ('/test.js',js),
    ('/1.jpg',jpg),
    ('/22.ico',ico),
    ]

    while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    # print(from_client_msg)
    request_str = from_client_msg
    path = request_str.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    for i in urlpatterns:
    if path == i[0]:
    i1

去掉了if判斷,因為請求文件和發送文件都是異步的,不需要等待結果,所以還可以做異步並發處理

import socket
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1',8001))
server.listen()

def html(conn):
    with open('04升級版.html', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def css(conn):
    with open('text.css', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def js(conn):
    with open('test.js', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def jpg(conn):
    with open('1.jpg', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def ico(conn):
    with open('22.ico', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

urlpatterns = [
    ('/',html),
    ('/text.css',css),
    ('/test.js',js),
    ('/1.jpg',jpg),
    ('/22.ico',ico),
]

while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    # print(from_client_msg)
    request_str = from_client_msg
    path = request_str.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    for i in urlpatterns:
        if path == i[0]:
            # i[1](conn)
            t = Thread(target=i[1],args=(conn,))
            t.start()
  1. 高級版

動態頁面,數據會發生變化的頁面

import socket
from threading import Thread
import time

server = socket.socket()
server.bind(('127.0.0.1',8001))
server.listen()

def html(conn):
    time_tag = str(time.time())
    with open('07高級版動態頁面.html', 'r',encoding='utf-8') as f:
        data = f.read()
    data = data.replace('$xxoo',time_tag)
    data = data.encode('utf-8')
    conn.send(data)
    conn.close()

def css(conn):
    with open('text.css', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def js(conn):
    with open('test.js', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def jpg(conn):
    with open('1.jpg', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

def ico(conn):
    with open('22.ico', 'rb') as f:
        data = f.read()
    conn.send(data)
    conn.close()

urlpatterns = [
    ('/',html),
    ('/text.css',css),
    ('/test.js',js),
    ('/1.jpg',jpg),
    ('/22.ico',ico),
]

while 1:
    conn,addr = server.accept()
    from_client_msg = conn.recv(1024).decode('utf-8')
    # print(from_client_msg)
    request_str = from_client_msg
    path = request_str.split('\r\n')[0].split(' ')[1]
    print(path)
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    for i in urlpatterns:
        if path == i[0]:
            # i[1](conn)
            t = Thread(target=i[1],args=(conn,))
            t.start()

07高級版動態頁面.html:

<body>

<h1>你想知道的我們都有</h1>
<h2>$xxoo</h2>
.....
</body>

通過字符串的替換,每次請求都會讀出來html文件,把事先寫好的一個字符串:$xxoo替換成 time_tag,也就是獲取的時間戳,這樣每次刷新頁面,時間戳都會改變,這樣頁面的數據就動態起來了
  1. wsgiref升級版

    ....
    path = request_str.split('\r\n')[0].split(' ')[1]
    ....
    conn.send(b'HTTP/1.1 200 ok\r\nk1:v1\r\n\r\n')
    ....

開發中的python web程序來說,一般會分為兩部分:服務器程序和應用程序。

  • 服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各種數據進行整理
  • 應用程序則負責具體的邏輯處理。為了方便應用程序的開發,就出現了眾多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。

WSGI協議:一種規范,web服務器程序和web應用程序之間傳輸信息要統一消息格式。常用的WSGI服務器有uwsgi、Gunicorn。而Python標准庫提供的獨立WSGI服務器叫wsgiref,Django開發環境用的就是這個模塊來做服務器

在socket接收請求信息、處理請求信息的時候,回復響應信息的格式的時候,有一個專門的模塊可以完成這件事情,就是wsgiref,它可以把請求的信息全部處理成一個字典,想要什么就可以通過字典取值來得到

import time
from wsgiref.simple_server import make_server
# wsgiref本身就是個web框架,提供了一些固定的功能(請求和響應信息的封裝,不需要我們自己寫原生的socket了也不需要咱們自己來完成請求信息的提取了,提取起來很方便)

def html():
    time_tag = str(time.time())
    with open('07高級版動態頁面.html', 'r',encoding='utf-8') as f:
        data = f.read()
    data = data.replace('$xxoo$',time_tag)
    data = data.encode('utf-8')
    return data

def css():
    with open('text.css', 'rb') as f:
        data = f.read()
    return data

def js():
    with open('test.js', 'rb') as f:
        data = f.read()
    return data

def jpg():
    with open('1.jpg', 'rb') as f:
        data = f.read()
    return data

def ico():
    with open('22.ico', 'rb') as f:
        data = f.read()
    return data

urlpatterns = [
    ('/', html),
    ('/text.css', css),
    ('/test.js', js),
    ('/1.jpg', jpg),
    ('/22.ico', ico),
]

#函數名字隨便起
def application(environ, start_response):
    '''
    :param environ: 是全部加工好的請求信息,加工成了一個字典,通過字典取值的方式就能拿到很多你想要拿到的信息
    :param start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數
    '''
    start_response('200 OK', [('k1','v1'),('k2','v2')]) # 新建添加回復的頭部
    path = environ['PATH_INFO']
    for i in urlpatterns:
        if path == i[0]:
            ret = i[1]()
            break
    else:
        ret = b'404 not found!'
    # 如果請求的路徑沒有一個能對應上,走else,返回404 not found
    return [ret]   # 得到結果,模塊內部把結果發送給網頁

httpd = make_server('127.0.0.1', 8080, application)

print('Serving HTTP on port 8080...')
# 開始監聽HTTP請求:
httpd.serve_forever()
  1. 連接數據庫版

先啟動mysql數據庫,創建一個庫(database),起名叫day53的庫

建立一個model.py文件,專門用來創建表(table)的

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,name char(10),age int not null );'
cursor.execute(sql)  # 執行

conn.commit()  # 提交
cursor.close()
conn.close()

建立一個insertdata.py文件,模擬插入數據(正常應該直接放在業務邏輯里)

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 = 'insert into userinfo(name,age) values ("yangzm",18);'
cursor.execute(sql)  # 執行

conn.commit()  # 提交
cursor.close()
conn.close()

建立一個showdata.py文件,專門用來查數據的,封裝成一個函數,返回查出來的數據

import pymysql

def showdata():   
    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 = 'select * from userinfo;'
    cursor.execute(sql)  # 執行
    data = cursor.fetchone()
    conn.commit()  # 提交
    cursor.close()
    conn.close()
    return data

此時查出來的是一個字典類型的數據

模擬這樣一個場景,就是用戶來訪問我的網站,注冊時提交了名字和年齡,保存在數據庫里(這個保存的邏輯應該是在業務邏輯里寫好的,本次只是模擬一下),現在想把這個數據庫里面的數據讀出來,放在html頁面里去,然后在前端的頁面展示

import time
from wsgiref.simple_server import make_server
from showdata import showdata
# wsgiref本身就是個web框架,提供了一些固定的功能(請求和響應信息的封裝,不需要我們自己寫原生的socket了也不需要咱們自己來完成請求信息的提取了,提取起來很方便)

def html():
    userinfo_data = showdata()  # 模塊導入使用
    with open('07高級版動態頁面.html', 'r',encoding='utf-8') as f:
        data = f.read()
    data = data.replace('$xxoo$',userinfo_data['name'])#從數據庫讀出來的數據,展示到頁面
    data = data.encode('utf-8')
    return data

def css():
    with open('text.css', 'rb') as f:
        data = f.read()
    return data

def js():
    with open('test.js', 'rb') as f:
        data = f.read()
    return data

def jpg():
    with open('1.jpg', 'rb') as f:
        data = f.read()
    return data

def ico():
    with open('22.ico', 'rb') as f:
        data = f.read()
    return data

urlpatterns = [
    ('/', html),
    ('/text.css', css),
    ('/test.js', js),
    ('/1.jpg', jpg),
    ('/22.ico', ico),
]

#函數名字隨便起
def application(environ, start_response):
    '''
    :param environ: 是全部加工好的請求信息,加工成了一個字典,通過字典取值的方式就能拿到很多你想要拿到的信息
    :param start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數
    '''
    start_response('200 OK', [('k1','v1'),('k2','v2')]) # 新建添加回復的頭部
    path = environ['PATH_INFO']
    for i in urlpatterns:
        if path == i[0]:
            ret = i[1]()
            break
    else:
        ret = b'404 not found!'
    # 如果請求的路徑沒有一個能對應上,走else,返回404 not found
    return [ret]

httpd = make_server('127.0.0.1', 8080, application)

print('Serving HTTP on port 8080...')
# 開始監聽HTTP請求:
httpd.serve_forever()

這樣,就完成了前端頁面顯示了從數據庫讀出來的數據的功能

  1. JinJa2高級版動態web框架

JinJa2 —— 模板渲染

動態頁面(也就是字符串的替換),有一個專門的工具: jinja2 模塊

安裝:
	pip install jinja2

用法:
	template = Template(data)  # 生成模板文件
	ret = template.render({"name": "於謙", "hobby_list": ["燙頭", "泡吧"]})  # 把數據填充到模板里面



from wsgiref.simple_server import make_server
from showdata import showdata
from jinja2 import Template

def html():
    userinfo_data = showdata()
    with open('10jinja2高級版動態web框架.html', 'r',encoding='utf-8') as f:
        data = f.read()
    tem = Template(data)
    data = tem.render({'userinfo':userinfo_data})
    # {'userinfo':{'id':1,'name':'yangzm','age':18}}

    data = data.encode('utf-8')
    return data

def css():
    with open('text.css', 'rb') as f:
        data = f.read()
    return data

def js():
    with open('test.js', 'rb') as f:
        data = f.read()
    return data

def jpg():
    with open('1.jpg', 'rb') as f:
        data = f.read()
    return data

def ico():
    with open('22.ico', 'rb') as f:
        data = f.read()
    return data

urlpatterns = [
    ('/', html),
    ('/text.css', css),
    ('/test.js', js),
    ('/1.jpg', jpg),
    ('/22.ico', ico),
]

#函數名字隨便起
def application(environ, start_response):
    '''
    :param environ: 是全部加工好的請求信息,加工成了一個字典,通過字典取值的方式就能拿到很多你想要拿到的信息
    :param start_response: 幫你封裝響應信息的(響應行和響應頭),注意下面的參數
    '''
    start_response('200 OK', [('k1','v1'),('k2','v2')]) # 新建添加回復的頭部
    path = environ['PATH_INFO']
    for i in urlpatterns:
        if path == i[0]:
            ret = i[1]()
            break
    else:
        ret = b'404 not found!'
    # 如果請求的路徑沒有一個能對應上,走else,返回404 not found
    return [ret]

httpd = make_server('127.0.0.1', 8080, application)

print('Serving HTTP on port 8080...')
# 開始監聽HTTP請求:
httpd.serve_forever()

<!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>Bootstrap 101 Template</title>
    <link href="text.css" rel="stylesheet">
    <link rel="icon" href="22.ico">
</head>
<body>

<h1>你想知道的我們都有</h1>

<h2>{{ userinfo }}</h2>
<!--userinfo就相當於我們查出來的那個數據字典{'id':1,'name':'yangzm','age':18}-->

<ul>
    {% for k,v in userinfo.items() %}
    <li>{{ k }}--{{ v }}</li>
    {% endfor %}
</ul>


一年的四季:
    <ul>
        <li>春</li>
        <li>夏</li>
        <li>秋</li>
        <li>冬</li>
    </ul>
<img src="1.jpg" alt="">
<script src="test.js"></script>
</body>
</html>

也能夠完成動態頁面的效果,在前端頁面顯示從數據庫讀出來的數據

11 .起飛版web框架


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM