咱們能夠這樣理解:全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。 這樣咱們就能夠本身實現Web框架了。html
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(1024) print(data) # 將瀏覽器發來的消息打印出來
conn.send(b"OK") conn.close()
能夠說Web服務本質上都是在這十幾行代碼基礎上擴展出來的。python
用戶的瀏覽器一輸入網址,會給服務端發送數據,那瀏覽器會發送什麼數據?怎麼發?這個誰來定? 你這個網站是這個規定,他那個網站按照他那個規定,這互聯網還能玩麼?mysql
因此,必須有一個統一的規則,讓你們發送消息、接收消息的時候有個格式依據,不能隨便寫。web
這個規則就是HTTP協議,之後瀏覽器發送請求信息也好,服務器回覆響應信息也罷,都要按照這個規則來。sql
HTTP協議主要規定了客戶端和服務器之間的通訊格式,那HTTP協議是怎麼規定消息格式的呢?數據庫
讓咱們首先打印下咱們在服務端接收到的消息是什麼。express
輸出結果:django
""" 請求首行 b'GET / HTTP/1.1\r\n 請求頭 Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Cache-Control: max-age=0\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9\r\n \r\n 請求體 ...... """
要想讓咱們本身寫的web server端正經起來,必需要讓咱們的Web server在給客戶端回覆消息的時候按照HTTP協議的規則加上響應狀態行,這樣咱們就實現了一個正經的Web框架了flask
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(1024) #給回覆的信息加上響應狀態行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') conn.send(b'hello world') print(data)
咱們經過十幾行代碼簡單地演示了web 框架的本質。後端
接下來就讓咱們繼續完善咱們的自定義web框架吧!
這樣就結束了嗎? 如何讓咱們的Web服務根據用戶請求的URL不一樣而返回不一樣的內容呢?
咱們能夠從請求相關數據裏面拿到請求URL的路徑,而後拿路徑作一個判斷...
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(1024) conn.send(b'HTTP/1.1 200 OK\r\n\r\n') data = data.decode('utf-8') # 把從瀏覽器那裏收到的字節類型的數據轉換成字符串
# print(data)
target_url = data.split('\r\n')[0].split(' ')[1] #按\r\n分割
# 根據不一樣的路徑返回不一樣內容
if target_url == '/index': # conn.send(b'index')
with open(r'D:\demo.html','rb') as f: conn.send(f.read()) elif target_url == '/login': conn.send(b'login') else: conn.send(b'404 error') conn.close()
基於wsgiref模塊以及文件拆分的特色:
若要開設新的資源
1.先在urls文件中寫url與函數的對應關係
2.再去views文件中寫對應的函數
urls.py:路由與視圖函數的對應關係
views.py:裏面就是放的一堆視圖函數(視圖函數能夠是函數也能夠是類)
templates文件夾:裏面放的就是一堆html文件(模板文件夾)
{{ xxx }} <p>{{xxx.username}}</p>
<p>{{xxx['password']}}</p>
<p>{{xxx.get('hobby')}}</p>
<p>{{xxx.get('hobby')[0]}}</p>
<p>{{xxx.get('hobby').1}}</p>
{%for user_dict in xxx %} <tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.hobby }}</td>
</tr> {% endfor %}
from views import * urls = [ ('/index',index), ('/login',login), ('/xxx',xxx), ('/get_time',get_time), ('/get_user',get_user), ('/get_info',get_info) ]
def index(env): return 'index'
def login(env): return 'login'
def error(env): return '404 error'
def xxx(env): return 'xxx'
import time def get_time(env): # 該函數須要返回一個html頁面
current_time = time.strftime('%Y-%m-%d %X') # 文件操做 讀取html文件
with open(r'F:\python\templates\02 get_time.html','r',encoding='utf-8') as f: data = f.read() # html文件內容 字符串
data = data.replace('gfdgsffsda',current_time) # 利用字符串的替換
return data from jinja2 import Template def get_user(env): user_dict = {'username':'jason','password':123,'hobby':['read','study','run']} with open(r'F:\python\templates\04 get_info.html','r',encoding='utf-8') as f: data = f.read() temp = Template(data) res = temp.render(xxx=user_dict) # 將user_dict傳遞給html頁面 在頁面上經過變量名xxx就可以獲取到user_dict
return res import pymysql def get_info(env): conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', password = '123', database = 'day49', charset = 'utf8', autocommit = True ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = "select * from userinfo" cursor.execute(sql) data = cursor.fetchall() # [{},{},{}]
# 將列表套字典的結構數據 直接傳遞給html頁面
with open(r'D:get_info.html','r',encoding='utf-8') as f: res = f.read() # 利用jinja2模塊
tmp = Template(res) # 利用對象的render方法 將數據直接傳遞給html頁面
res = tmp.render(xxx=data) return res
from wsgiref.simple_server import make_server from views import *
from urls import urls def run(env,response): """ :param env: 請求相關的全部數據 :param response: 響應相關的全部數據 :return: 瀏覽器可以接受的內容 """ response('200 OK',[]) # print(env) # env是一個大字典 裏面的PATH_INFO參數就是用戶輸入的後綴
target_url = env.get('PATH_INFO') # if target_url == '/index':
# # 一堆邏輯判斷
# return [b'index']
# elif target_url == '/login':
# return [b'login']
# 先定義一個變量 用來存儲可能匹配到的函數名
func = None # 1 for循環獲取一個個的url與函數對應關係的元組
for url in urls: # url = (),(),()
# 2 判斷當前用戶訪問的url與元組第一個元素是否一致
if target_url == url[0]: # 3 若是相等 說明有對應的後端邏輯代碼 將匹配到的函數名賦值給func
func = url[1] # 4 一旦用戶匹配上了響應的url 應該馬上結束當前for循環了 由於再循環就沒有意義
break
# 針對func是否有值 還須要判斷
if func: # 匹配上了 加括號直接調用
res = func(env) else: # 匹配404邏輯代碼
res = error(env) return [res.encode('utf-8')] # 返回函數的返回值
if __name__ == '__main__': # 監聽127.0.0.1:8080 一旦有客戶端來訪問 會馬上將make_server第三個參數加括號調用執行
server = make_server('127.0.0.1',8080,run) server.serve_forever() # 啓動服務端
python三大主流web框架
Django 優點:
Tornado 異步非阻塞,自然支持高併發 甚至能夠用它來開發遊戲服務器
Django版本:
推薦使用1.X版本里面的1.11.09~1.11.13
pip3 install django==1.11.11
#測試是否安裝成功
命令行輸入 django-admin
django-admin startproject mysite(項目名)
效果:建立了一個mysite的文件夾
mysite/ ├── manage.py # 管理文件
└── mysite # 項目目錄
├── __init__.py ├── settings.py # 配置
├── urls.py # 路由 --> URL和函數的對應關係
└── wsgi.py # runserver命令就使用wsgiref模塊作簡單的web server
python manage.py runserver # django默認的端口號是8000
Django 若啓動報錯「SyntaxError: Generator expression must be parenthesized」
報這個錯很大多是由於使用了Python3.7.0,而目前(2018-06-12)Python3.7.0和Django還有點兼容性問題。解決方案以下
Django 啓動時報錯 「UnicodeEncodeError ...」
報這個錯誤一般是由於計算機名爲中文,改爲英文的計算機名重啓下電腦就能夠了。
python manage.py startapp app01 #一般狀況下應該作到見名知意
app01
-- migrations 文件夾
-- __init__.py
-- admin.py
-- apps.py
-- models.py
-- tests.py
-- views.py
django實際上是一個專一於開發app的web框架,一個空的django項目就相似因而一所大學,app就相似於大學裏面的各個學院。
每一個app其實就相似於不一樣的功能模塊
購物網站
用戶相關 user
用戶相關的app
訂單相關 order
訂單相關的app
投訴相關 tousu
投訴相關的app
不一樣的功能模塊推薦使用不一樣的app去開發,django支持多app
mysite -mysite --__init__.py --settings.py 項目配置文件 --urls.py 路由視圖函數對應關係 項目的總路由 --wsgi.py -manage.py
app01 --migrations文件夾 數據庫改動記錄 --__init__.py --__init__.py --admin.py django後臺管理 --apps.py 註冊app相關 --models.py 模型類(ORM) --tests.py 測試文件 --views.py 視圖函數(******)
db.sqlite3 django自帶的一個小型用於本地測試的數據庫(對日期格式的數據不是很敏感)
注意:1.使用命令行建立的django項目是不會自動建立templates模板文件夾,只能本身手動建立
2.命令行建立的django項目不但沒有templates文件夾,配置文件中也沒有填寫路徑,而pycharm建立的會自動添加
容易犯的錯誤:代碼修改了始終沒有效果
1.在同一個端口起了多個服務 一直跑的是最開始的那個服務
2.瀏覽器緩存問題
解決瀏覽器緩存以下圖
補充:簡化命令的方式
項目配置文件夾註意事項:(註冊)
注意:建立app以後必定必定要先去setting文件中註冊
用pycharm建立的Django項目的配置文件
用命令行建立的Django項目的配置文件
HttpResponse:返回字符串
render:返回html頁面 並能夠給html頁面傳數據
模板的渲染(將數據在後端按照模板語法放入html對應的位置)
redirect:重定向
from django.shortcuts import render,HttpResponse,redirect # Create your views here.
def index(request): return HttpResponse('字符串') def login(request): return render(request,'templates文件夾下的html文件名',{'user_dict':{'username':'jason','password':123},'userxxx':'hello world'})) def home(request): # return redirect('http://www.baidu.com')
return redirect('/index')