web框架

一.導讀

1.web應用:運行在瀏覽器上的應用。html

2.c/s  b/s 架構:python

client/server:客戶端/服務器架構,C++mysql

brower/server:瀏覽器/服務器架構,Java,Pythonweb

3.python  web框架:sql

Django:socket用的是wsgiref,頁面路由用的本身寫的,模板渲染用的本身寫的,特色:功能全面。瀏覽器

Flask:socket用的是第三方,頁面路由用的本身寫的,模板渲染用的本身寫的,特色:小而輕。服務器

Tornado:socket用的是本身寫的,頁面路由用的本身寫的,模板渲染用的本身寫的,特色:支持高併發。架構

二.HTTP協議

1.什麼是http協議?

HTTP(HyperText Transport Protocol)指的是超文本傳輸協議,它是基於TCP/IP協議基礎上的應用層協議,底層實現仍是socket,它是基於請求-響應模式:通訊必定是從客戶端開始,服務器端接收到客戶端必定會作出對應響應。併發

無鏈接:一次鏈接只完成一次請求-響應,請求-響應完畢後會當即斷開鏈接。app

無狀態:協議不對任何一次通訊狀態和任何數據進行保存。

2.http工做原理(事務)

一次http操做稱之爲一個事務,工做過程能夠分爲四步:

1.客戶端與服務器創建鏈接;

2.客戶端發生一個http協議指定格式的請求;

3.服務器端接收請求後,響應一個http協議指定格式的響應;

4.客戶端將服務器的響應顯示展示給用戶。

import socket PORT = 9999 server = socket.socket() server.bind(('127.0.0.1', PORT)) server.listen(5) print("服務器啓動:http://127.0.0.1:%s" % PORT) while True: brower, addr = server.accept() req_data = brower.recv(1024).decode('utf-8') # print(req_data)

    # 響應報文
    # 遵循http協議返回數據:響應行 響應頭 響應體
    brower.send(b'HTTP/1.1 200 OK\r\n')  # 響應行(必須),以\r\n結束
    brower.send(b'Content-type:text/html\r\n')  # 響應頭(可選),服務於響應頭
    brower.send(b'\r\n')  # 響應規則與響應體內容之間還須要一個\r\n進行分割
    brower.send(b'hahaha')  # 響應體(可選)
    brower.send(b'<h1>hello world</h1>') brower.close() # 必須關閉每一次的鏈接


# 請求報文
''' GET / HTTP/1.1 Host: 127.0.0.1:9999 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 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 # /favicon.ico指的是頁面頭的圖標 Host: 127.0.0.1:9999 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36 Accept: image/webp,image/apng,image/*,*/*;q=0.8 Referer: http://127.0.0.1:9999/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 '''
基礎b/s架構

3.http處理響應

import socket PORT = 9999 server = socket.socket() server.bind(('127.0.0.1', PORT)) server.listen(5) print("服務器啓動:http://127.0.0.1:%s" % PORT) def index(): pass


def login(): pass


def ico(): with open('1.jpg', 'rb') as f: data = f.read() return data func_dic = { '/': index, '/index': index, '/login': login, '/favicon.ico': ico } while True: brower, addr = server.accept() req_data = brower.recv(1024).decode('utf-8') # print(req_data)

    # 響應報文
    # 遵循http協議返回數據:響應行 響應頭 響應體
    brower.send(b'HTTP/1.1 200 OK\r\n')  # 響應行(必須),以\r\n結束
    brower.send(b'Content-type:text/html\r\n')  # 響應頭(可選),服務於響應頭
    brower.send(b'\r\n')  # 響應規則與響應體內容之間還須要一個\r\n進行分割

    # GET / HTTP/1.1
    # GET /favicon.ico HTTP/1.1
    path = req_data.split('\r\n')[0].split(' ')[1]  # 請求路徑
    # 根據路徑,處理不一樣的請求方法
    if path in func_dic: res_dic = func_dic[path]() res_dic = b'<h1 style="text-align: center">404</h>' brower.send(res_dic) # 響應體(可選)
    brower.close()  # 必須關閉每一次的鏈接
請求分配

基於上面的基礎b/s架構,能夠根據請求http協議數據,解析出請求路徑,根據具體路徑完成業務邏輯,的方法,完成對應的響應。

1.因爲業務邏輯會不斷的增長,因此業務邏輯要進行分層單獨處理;

2.路徑與業務處理方法對應關係也會愈來愈多,愈來愈複雜,也能夠分離單獨處理;

3.自定義服務器功能不健全,穩定性差,能夠選擇第三方

server.py import socket from wsgi協議.urls import url_dic PORT = 9999 server = socket.socket() server.bind(('127.0.0.1', PORT)) server.listen(5) print("服務器啓動:http://127.0.0.1:%s" % PORT) while True: brower, addr = server.accept() req_data = brower.recv(1024).decode('utf-8') # print(req_data)

    # 響應報文
    # 遵循http協議返回數據:響應行 響應頭 響應體
    brower.send(b'HTTP/1.1 200 OK\r\n')  # 響應行(必須),以\r\n結束
    brower.send(b'Content-type:text/html\r\n')  # 響應頭(可選),服務於響應頭
    brower.send(b'\r\n')  # 響應規則與響應體內容之間還須要一個\r\n進行分割

    # GET / HTTP/1.1
    # GET /favicon.ico HTTP/1.1
    url = req_data.split('\r\n')[0].split(' ')[1]  # 請求路徑
    # 根據路徑,處理不一樣的請求方法
    if url in url_dic: res_dic = url_dic[url]() res_dic = b'<h1 style="text-align: center">404</h>'  # 響應錯誤時返回404
    brower.send(res_dic)  # 響應體(可選)
    brower.close()  # 必須關閉每一次的鏈接
 urls.py from wsgi協議.views import * url_dic = { '/': index, '/index': index, '/login': login, '/favicon.ico': ico } views.py def index(): pass


def login(): pass


def ico(): with open('1.jpg', 'rb') as f: data = f.read() return data
分層請求分配處理

4.狀態碼

# 1打頭:消息通知
# 2打頭:請求成功
# 3打頭:重定向
# 4打頭:客戶端錯誤
# 5打頭:服務器端錯誤

三.WSGI協議

利用第三方wsgiref服務器完成http請求-響應:

經過wsgiref模塊建立server時,有三個參數分別是:Host,Port,app,其中app時一個回調函數,該回調函數有兩個參數:environ和response;environ是一個字典,請求的數據都被解析在該字典中,用response來規定http響應的結果。

server.py from wsgiref import simple_server from wsgi協議.urls import url_dic PORT = 8888


# 回調函數
def app(environ, response): # 請求的數據都被解析在environ字典中
    # 請求方式的key:REQUEST_METHOD # 'REQUEST_METHOD': 'GET'
    # 請求的路徑的key:PATH_INFO # 'PATH_INFO': '/'
    print(environ) # 用response來規定http響應的結果
    response('200 OK', [('Content-type', 'text/html')]) # 數據的獲取

    # 解析給key,獲得數據
    method = environ['REQUEST_METHOD']  # 請求方法
    res_dic = {} url = ''
    if method == 'GET': url = environ['PATH_INFO']  # 請求路徑
        # 在GET方法中:數據在environ中的QUERY_STRING對應的value
        res_str = environ['QUERY_STRING'] if res_str: res_list = res_str.split('&') for i in res_list: data_list = i.split('=') res_dic[data_list[0]] = data_list[1] elif method == 'POST':  # 在POST方法中:數據存放的io流'wsgi.input': <_io.BufferedReader name=552>;數據長度'CONTENT_LENGTH': '40'
        length = int(environ['CONTENT_LENGTH']) if length == 0: return res_str = environ['wsgi.input'].read(length).decode('utf-8') res_list = res_str.split('&') for i in res_list: data_list = i.split('=') if i is res_list[-1]: url = '/' + data_list[0] # print(url)
                continue res_dic[data_list[0]] = data_list[1] # print(res_dic)
 req_dic = b'<h1 style="text-align: center">404</h1>'
    if url in url_dic: req_dic = url_dic[url](res_dic) # print(res_dic)

    # 返回的是裝有二進制數據的列表
    return [req_dic] if __name__ == '__main__': server = simple_server.make_server('127.0.0.1', PORT, app=app)  # 經過wsgiref建立server
    print('服務器啓動:http://127.0.0.1:%s' % PORT) # 保持server一直運行
 server.serve_forever() views.py import pymysql from jinja2 import Template def execute(sql, args): conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='root', db='db1', charset='utf8', autocommit=True ) cursor = conn.cursor(pymysql.cursors.DictCursor) affect_row = cursor.execute(sql, args=args) return affect_row def index(dic): pass


def login(dic): # print(dic)
    name = dic['usr'] pwd = dic['pwd'] sql = "select * from user where name=%s and pwd=%s" args = [name, pwd] row = execute(sql, args) with open('login.html', 'rt') as f: msg = f.read() tem = Template(msg) if row: res = 'login success'
    else: res = 'login failed' msg = tem.render(result=res) return msg.encode('utf-8') def register(dic): pass


def ico(dic): with open('timg.jpg', 'rb') as f: data = f.read() return data login.html <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title</title>
</head>
<body> {{ result }} </body>
</html> urls.py from wsgi協議.views import * url_dic = { '/': index, '/index': index, '/login': login, '/favicon.ico': ico } deom.html <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8888" method="post">
    <input type="text" name="usr">
    <br>
    <input type="password" name="pwd">
    <br>
    <input type="submit" value="login" name="login">
</form>
</body>
</html>
簡單登陸功能
相關文章
相關標籤/搜索