web 框架

WEB框架介紹

框架,即framework,特指爲解決一個開放性問題而設計的具備必定約束性的支撐結構,使用框架能夠幫你快速開發特定的系統,簡單地說,就是你用別人搭建好的舞臺來作表演。html

對於全部的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端python

 

import socket

def handle_request(client):

    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8"))

def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':

    main()

      最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。mysql

若是要動態生成HTML,就須要把上述步驟本身來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,若是咱們本身來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。web

      正確的作法是底層代碼由專門的服務器軟件實現,咱們用Python專一於生成HTML文檔。由於咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口,讓咱們專心用Python編寫Web業務。sql

這個接口就是WSGI:Web Server Gateway Interface。數據庫

HTTP協議

:簡單理解成  規定消息的格式瀏覽器

  全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。用戶的瀏覽器一輸入網址,會給服務端發送數據,那瀏覽器會發送什麼數據?怎麼發?這個誰來定?HTTP協議。HTTP協議就是解決這個問題,它規定了發送消息和接收消息的格式服務器

  每一個HTTP請求和響應都遵循相同的格式,一個HTTP包含Header和Body兩部分,其中Body是可選的。HTTP響應的Header中有一個Content-Type代表響應的內容格式。如text/html表示HTML網頁。
(1)HTTP請求app

HTTP GET請求的格式:框架

HTTP POST請求格式:

(2)HTTP響應

  HTTP響應的格式:

 

標準Web框架

 

#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server
 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, web!</h1>'
if __name__ == '__main__':
        httpd = make_server('', 8000, RunServer)
        print "Serving HTTP on port 8000..."
httpd.serve_forever()
View Code

 

自定義Web框架

 

from wsgiref.simple_server import make_server
 
def login():
    return 'login'
 
def index():
    data = open('index.html','r').read()
    return data
 
url = (
    ('/login/',login),
('/index/',index),
)
 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
 
    geturl = environ['PATH_INFO']
    for item in url:
        if item[0] == geturl:
            return  item[1]()
    else:
        return '404'
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
httpd.serve_forever()
View Code

 

 

 

 

三、自定義WEB框架

  WEB應用本質就是一個sockect服務端,只要讓咱們的Web框架在給客戶端回覆響應的時候按照HTTP協議的規則加上響應頭,這樣咱們就實現了一個正經的Web框架。以下簡單實例:開啓服務端後,在瀏覽器上輸入網址:127.0.0.1:8090/index/後就會向瀏覽器返回:這是主頁內容

from socket import socket
server=socket()
server.bind(("127.0.0.1",8090))
server.listen(5)
while True:
    conn,addr=server.accept()
    data = conn.recv(1024).decode()                                                      #data爲請求的HTTP格式
    print(data)
    header=data.split("\r\n\r\n")[0]                                                     #得到請求header部分
    temp=header.split("\r\n")[0]                                                         #得到header中包含請求路徑的第一行
    url=temp.split(" ")[1]                                                               #得到請求路徑
    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n')       #返回HTTP響應格式內容
#根據路徑不一樣返回不一樣的內容
    if url=="/index/":
        response="這是主頁"
    else:
        response="404"
    conn.send(bytes(response,encoding="utf-8"))
View Code

以下爲上述實例接收到HTTP請求的data內容:

GET /index/ HTTP/1.1                                              #header部分
Host: 127.0.0.1:8090
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9


GET /favicon.ico HTTP/1.1                                         #body部分
Host: 127.0.0.1:8090
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://127.0.0.1:8090/index/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
View Code

上述實例咱們能夠從請求頭裏面拿到請求的URL,而後作一個判斷,咱們的Web服務根據用戶請求的URL不一樣而返回不一樣的內容。可是問題又來了,若是有不少不少頁面怎麼辦?難道要挨個判斷?固然不用,咱們有更聰明的辦法

from socket import socket
server=socket()
server.bind(("127.0.0.1",8090))
server.listen(5)
def index():
    return "這是主頁"
def info():
    return "這是我的信息頁"
func_list=[
    ("/index/",index),
    ("/info/",info)
  ]
while True:
    conn,addr=server.accept()
    data = conn.recv(1024).decode()
    header=data.split("\r\n\r\n")[0]
    temp=header.split("\r\n")[0]
    url=temp.split(" ")[1]
    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n')
    func_name=None
    for i in func_list:
        if url==i[0]:
            func_name=i[1]
            break

    if func_name:
        response=func_name()
    else:
        response="404"
    conn.send(bytes(response,encoding="utf-8"))

完美解決了不一樣URL返回不一樣內容的問題。可是我不想僅僅返回幾個字符串,我想給瀏覽器返回完整的HTML內容,這又該怎麼辦呢?沒問題,不論是什麼內容,最後都是轉換成字節數據發送出去的。我能夠打開HTML文件,讀取出它內部的二進制數據,而後發送給瀏覽器。

from socket import socket
server=socket()
server.bind(("127.0.0.1",8090))
server.listen(5)
def index():
    with open("index.html",encoding="utf-8") as f:
        data_html=f.read()                                         #讀取html程序,本質是字符串
    import pymysql
    conn = pymysql.connect(host='localhost', user='root', password='', database='day65', charset='utf8')
    cur = conn.cursor(cursor=pymysql.cursors.DictCursor)           # 設置查詢結果以字典形式顯示
    sql = "select id,name,balance from user"
    cur.execute(sql)
    use_list = cur.fetchall()
    print(use_list)#[{'id': 1, 'name': 'egon', 'balance': 10000}, {'id': 2, 'name': 'alex', 'balance': 2000}, {'id': 3, 'name': 'wsb', 'balance': 20000}]
    ret=""
    for i in use_list:
        ret+="""
         <tr>
            <td>{0}</td>
            <td>{1}</td>
            <td>{2}</td>
        </tr>
        """.format(i["id"],i["name"],i["balance"])
    cur.close()
    conn.close()
    data_new=data_html.replace("@@xx@@",ret)                        #將html中的佔位內容用數據庫中查詢的結果組成的字符替換
    return data_new                                                 #返回替換數據的html字符串

index()
def info():
    return "這是我的信息頁"
func_list=[
    ("/index/",index),
    ("/info/",info)
    ]
while True:
    conn,addr=server.accept()
    data = conn.recv(1024).decode()
    header=data.split("\r\n\r\n")[0]
    temp=header.split("\r\n")[0]
    url=temp.split(" ")[1]
    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n')
    func_name=None
    for i in func_list:
        if url==i[0]:
            func_name=i[1]
            break
    if func_name:
        response=func_name()
    else:
        response="404"
    conn.send(bytes(response,encoding="utf-8"))
View Code

  上述代碼模擬了一個web服務的本質,而對於真實開發中的Python Web程序來講,通常分爲兩部分:服務器程序和應用程序。服務器程序負責對Socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架。

  不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。這樣,服務器程序就須要爲不一樣的框架提供不一樣的支持。這樣混亂的局面不管對於服務器仍是框架,都是很差的。對服務器來講,須要支持各類不一樣框架,對框架來講,只有支持它的服務器才能被開發出的應用使用。這時候,標準化就變得尤其重要。一旦標準肯定,雙方根據約定的標準各自進行開發便可。WSGI(Web Server Gateway Interface)就是這樣一種規範,它定義了使用Python編寫的Web APP與Web Server之間接口格式,實現Web APP與Web Server間的解耦。

 

模板渲染jinja2

from wsgiref.simple_server import make_server
import jinja2

def index():
    with open("index.html", encoding="utf8") as f:
        data = f.read()

    # 鏈接數據庫
    import pymysql
    # 鏈接
    conn = pymysql.connect(host="localhost", user="root", password="123456", database="day60", charset="utf8")  # 沒有-
    # 獲取光標
    cursor = conn.cursor()
    # 寫sql語句
    sql = "select name, pwd from userinfo where id =1;"
    cursor.execute(sql)
    ret = cursor.fetchone()
    print(ret)
    # 將數據庫中的數據填充到HTML頁面
    new1_data = data.replace("@@2@@", ret[0])
    new2_data = new1_data.replace("##3##", ret[1])
    return new2_data

def home():
    return "這是home頁面"

def userlist():
    with open("userlist.html", encoding="utf8") as f:
        data = f.read()
    # 生成了一個jinja2的模板對象
    template = jinja2.Template(data)
    # 至關於字符串替換
    new_data = template.render({
        "user_list": [
            {"name": "jianchao", "pwd": "1234"},
            {"name": "liyan", "pwd": "5678"}
        ]
    })
    return new_data

def login():
    with open("login.html", encoding="utf8") as f:
        data = f.read()
    import time
    time_str = str(time.time())
    new_data = data.replace("@@2@@", time_str)
    return new_data

URL_FUNC = [
    ("/index/", index),
    ("/home/", home),
    ("/login/", login),
    ("/userlist/", userlist),
]

def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 設置HTTP響應的狀態碼和頭信息
    url = environ['PATH_INFO']  # 取到用戶輸入的url
    print("--->url:", url)
    # 根據url的不一樣,返回不一樣的內容
    func_name = None
    for i in URL_FUNC:
        if url == i[0]:  # 若是能找到對應關係,就把函數名拿到
            func_name = i[1]
            break
    # 拿到能夠執行的函數,執行函數拿到結果
    if func_name:
        body = func_name()
    else:
        body = "404找不到這個頁面"

    return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]


if __name__ == '__main__':
    httpd = make_server('', 9000, run_server)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()
相關文章
相關標籤/搜索