<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Web框架原理

      一、Web框架本質

      二、服務器程序和應用程序

      三、Django

      四、Django基礎三件套

      五、重定向是怎么回事

      一、Web框架本質

      我們可以這樣理解:所有的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。 這樣我們就可以自己實現Web框架了。

      中文官網: https://docs.djangoproject.com/zh-hans/4.0/

      # 半成品自定義web框架
      import socket
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 80))
      sk.listen()
      
      
      while True:
          conn, addr = sk.accept()
          data = conn.recv(8096)
          conn.send(b"OK")
          conn.close()

      可以說Web服務本質上都是在這十幾行代碼基礎上擴展出來的。這段代碼就是它們的祖宗。

      用戶的瀏覽器一輸入網址,會給服務端發送數據,那瀏覽器會發送什么數據?怎么發?這個誰來定? 你這個網站是這個規定,他那個網站按照他那個規定,這互聯網還能玩么?

      所以,必須有一個統一的規則,讓大家發送消息、接收消息的時候有個格式依據,不能隨便寫。

      這個規則就是HTTP協議,以后瀏覽器發送請求信息也好,服務器回復響應信息也罷,都要按照這個規則來。

      HTTP協議主要規定了客戶端和服務器之間的通信格式,那HTTP協議是怎么規定消息格式的呢?

      讓我們首先打印下我們在服務端接收到的消息是什么。

      import socket
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 80))
      sk.listen()
      
      
      while True:
          conn, addr = sk.accept()
          data = conn.recv(8096)
          print(data)  # 將瀏覽器發來的消息打印出來
          conn.send(b"OK")
          conn.close()

       輸出:

      b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nDNT: 1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93ZH3zv\r\n\r\n'

      然后我們再看一下我們訪問博客園官網時瀏覽器收到的響應信息是什么。

      響應相關信息可以在瀏覽器調試窗口的network標簽頁中看到。

       點擊view source之后顯示如下圖:

       我們發現收發的消息需要按照一定的格式來,這里就需要了解一下HTTP協議了。

      HTTP協議介紹

      HTTP協議對收發消息的格式要求

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

      HTTP GET請求的格式:

       

      HTTP響應的格式:

       處女版自定義web框架

      經過上面的補充學習,我們知道了要想讓我們自己寫的web server端正經起來,必須要讓我們的Web server在給客戶端回復消息的時候按照HTTP協議的規則加上響應狀態行,這樣我們就實現了一個正經的Web框架了。

      import socket
      
      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      sock.bind(('127.0.0.1', 8000))
      sock.listen()
      
      while True:
          conn, addr = sock.accept()
          data = conn.recv(8096)
          # 給回復的消息加上響應狀態行
          conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
          conn.send(b"OK")
          conn.close()

      我們通過十幾行代碼簡單地演示了web 框架的本質。

      接下來就讓我們繼續完善我們的自定義web框架吧!

      二、根據不同的路徑返回不同的內容

      這樣就結束了嗎? 如何讓我們的Web服務根據用戶請求的URL不同而返回不同的內容呢?

      小事一樁,我們可以從請求相關數據里面拿到請求URL的路徑,然后拿路徑做一個判斷...

      """
      根據URL中不同的路徑返回不同的內容
      """
      
      import socket
      sk = socket.socket()
      sk.bind(("127.0.0.1", 8080))  # 綁定IP和端口
      sk.listen()  # 監聽
      
      
      while 1:
          # 等待連接
          conn, add = sk.accept()
          data = conn.recv(8096)  # 接收客戶端發來的消息
          # 從data中取到路徑
          data = str(data, encoding="utf8")  # 把收到的字節類型的數據轉換成字符串
          # 按\r\n分割
          data1 = data.split("\r\n")[0]
          url = data1.split()[1]  # url是我們從瀏覽器發過來的消息中分離出的訪問路徑
          conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因為要遵循HTTP協議,所以回復的消息也要加狀態行
          # 根據不同的路徑返回不同內容
          if url == "/index/":
              response = b"index"
          elif url == "/home/":
              response = b"home"
          else:
              response = b"404 not found!"
      
          conn.send(response)
          conn.close()

      根據不同的路徑返回不同的內容--函數版

      上面的代碼解決了不同URL路徑返回不同內容的需求。

      但是問題又來了,如果有很多很多路徑要判斷怎么辦?難道要挨個寫if判斷? 當然不用,我們有更聰明的辦法。

      """
      根據URL中不同的路徑返回不同的內容--函數版
      """
      
      import socket
      sk = socket.socket()
      sk.bind(("127.0.0.1", 8080))  # 綁定IP和端口
      sk.listen()  # 監聽
      
      
      # 將返回不同的內容部分封裝成函數
      def index(url):
          s = "這是{}頁面!".format(url)
          return bytes(s, encoding="utf8")
      
      
      def home(url):
          s = "這是{}頁面!".format(url)
          return bytes(s, encoding="utf8")
      
      
      while 1:
          # 等待連接
          conn, add = sk.accept()
          data = conn.recv(8096)  # 接收客戶端發來的消息
          # 從data中取到路徑
          data = str(data, encoding="utf8")  # 把收到的字節類型的數據轉換成字符串
          # 按\r\n分割
          data1 = data.split("\r\n")[0]
          url = data1.split()[1]  # url是我們從瀏覽器發過來的消息中分離出的訪問路徑
          conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因為要遵循HTTP協議,所以回復的消息也要加狀態行
          # 根據不同的路徑返回不同內容,response是具體的響應體
          if url == "/index/":
              response = index(url)
          elif url == "/home/":
              response = home(url)
          else:
              response = b"404 not found!"
      
          conn.send(response)
          conn.close()

      根據不同的路徑返回不同的內容--函數進階版

      看起來上面的代碼還是要挨個寫if判斷,怎么辦?我們還是有辦法!(只要思想不滑坡,方法總比問題多!)

      """
      根據URL中不同的路徑返回不同的內容--函數進階版
      """
      
      import socket
      sk = socket.socket()
      sk.bind(("127.0.0.1", 8080))  # 綁定IP和端口
      sk.listen()  # 監聽
      
      
      # 將返回不同的內容部分封裝成函數
      def index(url):
          s = "這是{}頁面!".format(url)
          return bytes(s, encoding="utf8")
      
      
      def home(url):
          s = "這是{}頁面!".format(url)
          return bytes(s, encoding="utf8")
      
      
      # 定義一個url和實際要執行的函數的對應關系
      list1 = [
          ("/index/", index),
          ("/home/", home),
      ]
      
      while 1:
          # 等待連接
          conn, add = sk.accept()
          data = conn.recv(8096)  # 接收客戶端發來的消息
          # 從data中取到路徑
          data = str(data, encoding="utf8")  # 把收到的字節類型的數據轉換成字符串
          # 按\r\n分割
          data1 = data.split("\r\n")[0]
          url = data1.split()[1]  # url是我們從瀏覽器發過來的消息中分離出的訪問路徑
          conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因為要遵循HTTP協議,所以回復的消息也要加狀態行
          # 根據不同的路徑返回不同內容
          func = None  # 定義一個保存將要執行的函數名的變量
          for i in list1:
              if i[0] == url:
                  func = i[1]
                  break
          if func:
              response = func(url)
          else:
              response = b"404 not found!"
      
          # 返回具體的響應消息
          conn.send(response)
          conn.close()

      返回具體的HTML文件

      完美解決了不同URL返回不同內容的問題。 但是我不想僅僅返回幾個字符串,我想給瀏覽器返回完整的HTML內容,這又該怎么辦呢?

      沒問題,不管是什么內容,最后都是轉換成字節數據發送出去的。 我們可以打開HTML文件,讀取出它內部的二進制數據,然后再發送給瀏覽器。

      """
      根據URL中不同的路徑返回不同的內容--函數進階版
      返回獨立的HTML頁面
      """
      
      import socket
      sk = socket.socket()
      sk.bind(("127.0.0.1", 8080))  # 綁定IP和端口
      sk.listen()  # 監聽
      
      
      # 將返回不同的內容部分封裝成函數
      def index(url):
          # 讀取index.html頁面的內容
          with open("index.html", "r", encoding="utf8") as f:
              s = f.read()
          # 返回字節數據
          return bytes(s, encoding="utf8")
      
      
      def home(url):
          with open("home.html", "r", encoding="utf8") as f:
              s = f.read()
          return bytes(s, encoding="utf8")
      
      
      # 定義一個url和實際要執行的函數的對應關系
      list1 = [
          ("/index/", index),
          ("/home/", home),
      ]
      
      while 1:
          # 等待連接
          conn, add = sk.accept()
          data = conn.recv(8096)  # 接收客戶端發來的消息
          # 從data中取到路徑
          data = str(data, encoding="utf8")  # 把收到的字節類型的數據轉換成字符串
          # 按\r\n分割
          data1 = data.split("\r\n")[0]
          url = data1.split()[1]  # url是我們從瀏覽器發過來的消息中分離出的訪問路徑
          conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因為要遵循HTTP協議,所以回復的消息也要加狀態行
          # 根據不同的路徑返回不同內容
          func = None  # 定義一個保存將要執行的函數名的變量
          for i in list1:
              if i[0] == url:
                  func = i[1]
                  break
          if func:
              response = func(url)
          else:
              response = b"404 not found!"
      
          # 返回具體的響應消息
          conn.send(response)
          conn.close()

      讓網頁動態起來

      這網頁能夠顯示出來了,但是都是靜態的啊。頁面的內容都不會變化的,我想要的是動態網站。

      沒問題,我也有辦法解決。我選擇使用字符串替換來實現這個需求。(這里使用時間戳來模擬動態的數據)

      """
      根據URL中不同的路徑返回不同的內容--函數進階版
      返回HTML頁面
      讓網頁動態起來
      """
      
      import socket
      import time
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 8080))  # 綁定IP和端口
      sk.listen()  # 監聽
      
      
      # 將返回不同的內容部分封裝成函數
      def index(url):
          with open("index.html", "r", encoding="utf8") as f:
              s = f.read()
              now = str(time.time())
              s = s.replace("@@oo@@", now)  # 在網頁中定義好特殊符號,用動態的數據去替換提前定義好的特殊符號
          return bytes(s, encoding="utf8")
      
      
      def home(url):
          with open("home.html", "r", encoding="utf8") as f:
              s = f.read()
          return bytes(s, encoding="utf8")
      
      
      # 定義一個url和實際要執行的函數的對應關系
      list1 = [
          ("/index/", index),
          ("/home/", home),
      ]
      
      while 1:
          # 等待連接
          conn, add = sk.accept()
          data = conn.recv(8096)  # 接收客戶端發來的消息
          # 從data中取到路徑
          data = str(data, encoding="utf8")  # 把收到的字節類型的數據轉換成字符串
          # 按\r\n分割
          data1 = data.split("\r\n")[0]
          url = data1.split()[1]  # url是我們從瀏覽器發過來的消息中分離出的訪問路徑
          conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因為要遵循HTTP協議,所以回復的消息也要加狀態行
          # 根據不同的路徑返回不同內容
          func = None  # 定義一個保存將要執行的函數名的變量
          for i in list1:
              if i[0] == url:
                  func = i[1]
                  break
          if func:
              response = func(url)
          else:
              response = b"404 not found!"
      
          # 返回具體的響應消息
          conn.send(response)
          conn.close()

      服務器程序和應用程序

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

      服務器程序負責對socket服務器進行封裝,并在請求到來時,對請求的各種數據進行整理。

      應用程序則負責具體的邏輯處理。為了方便應用程序的開發,就出現了眾多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。

       

      這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對于服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。

      這時候,標準化就變得尤為重要。我們可以設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那么他們就可以配合使用。一旦標準確定,雙方各自實現。這樣,服務器可以支持更多支持標準的框架,框架也可以使用更多支持標準的服務器。

      WSGI(Web Server Gateway Interface)就是一種規范,它定義了使用Python編寫的web應用程序與web服務器程序之間的接口格式,實現web應用程序與web服務器程序間的解耦。

      常用的WSGI服務器有uwsgi、Gunicorn。而Python標準庫提供的獨立WSGI服務器叫wsgiref,Django開發環境用的就是這個模塊來做服務器。

       

      wsgiref

      我們利用wsgiref模塊來替換我們自己寫的web框架的socket server部分:

      """
      根據URL中不同的路徑返回不同的內容--函數進階版
      返回HTML頁面
      讓網頁動態起來
      wsgiref模塊版
      """
      
      import time
      from wsgiref.simple_server import make_server
      
      
      # 將返回不同的內容部分封裝成函數
      def index(url):
          with open("index.html", "r", encoding="utf8") as f:
              s = f.read()
              now = str(time.time())
              s = s.replace("@@oo@@", now)
          return bytes(s, encoding="utf8")
      
      
      def home(url):
          with open("home.html", "r", encoding="utf8") as f:
              s = f.read()
          return bytes(s, encoding="utf8")
      
      
      # 定義一個url和實際要執行的函數的對應關系
      list1 = [
          ("/index/", index),
          ("/home/", home),
      ]
      
      
      def run_server(environ, start_response):
          start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 設置HTTP響應的狀態碼和頭信息
          url = environ['PATH_INFO']  # 取到用戶輸入的url
          func = None
          for i in list1:
              if i[0] == url:
                  func = i[1]
                  break
          if func:
              response = func(url)
          else:
              response = b"404 not found!"
          return [response, ]
      
      
      if __name__ == '__main__':
          httpd = make_server('127.0.0.1', 8090, run_server)
          print("我在8090等你哦...")
          httpd.serve_forever()
      View Code

      jinja2

      上面的代碼實現了一個簡單的動態,我完全可以從數據庫中查詢數據,然后去替換我html中的對應內容,然后再發送給瀏覽器完成渲染。 這個過程就相當于HTML模板渲染數據。 本質上就是HTML內容中利用一些特殊的符號來替換要展示的數據。 我這里用的特殊符號是我定義的,其實模板渲染有個現成的工具: jinja2

      下載jinja2:

      pip install jinja2
      <!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>Title</title>
      </head>
      <body>
          <h1>姓名:{{name}}</h1>
          <h1>愛好:</h1>
          <ul>
              {% for hobby in hobby_list %}
              <li>{{hobby}}</li>
              {% endfor %}
          </ul>
      </body>
      </html>
      
      index2.html文件
      index2.html文件

      使用jinja2渲染index2.html文件:

      from wsgiref.simple_server import make_server
      from jinja2 import Template
      
      
      def index():
          with open("index2.html", "r") as f:
              data = f.read()
          template = Template(data)  # 生成模板文件
          ret = template.render({"name": "Alex", "hobby_list": ["燙頭", "泡吧"]})  # 把數據填充到模板里面
          return [bytes(ret, encoding="utf8"), ]
      
      
      def home():
          with open("home.html", "rb") as f:
              data = f.read()
          return [data, ]
      
      
      # 定義一個url和函數的對應關系
      URL_LIST = [
          ("/index/", index),
          ("/home/", home),
      ]
      
      
      def run_server(environ, start_response):
          start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 設置HTTP響應的狀態碼和頭信息
          url = environ['PATH_INFO']  # 取到用戶輸入的url
          func = None  # 將要執行的函數
          for i in URL_LIST:
              if i[0] == url:
                  func = i[1]  # 去之前定義好的url列表里找url應該執行的函數
                  break
          if func:  # 如果能找到要執行的函數
              return func()  # 返回函數的執行結果
          else:
              return [bytes("404沒有該頁面", encoding="utf8"), ]
      
      
      if __name__ == '__main__':
          httpd = make_server('', 8000, run_server)
          print("Serving HTTP on port 8000...")
          httpd.serve_forever()

      現在的數據是我們自己手寫的,那可不可以從數據庫中查詢數據,來填充頁面呢?

      使用pymysql連接數據庫:

      conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
      cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
      cursor.execute("select name, age, department_id from userinfo")
      user_list = cursor.fetchall()
      cursor.close()
      conn.close()

      創建一個測試的user表:

      CREATE TABLE user(
        id int auto_increment PRIMARY KEY,
        name CHAR(10) NOT NULL,
        hobby CHAR(20) NOT NULL
      )engine=innodb DEFAULT charset=UTF8;

      模板的原理就是字符串替換,我們只要在HTML頁面中遵循jinja2的語法規則寫上,其內部就會按照指定的語法進行相應的替換,從而達到動態的返回內容。

      三、Django

      Django官網下載頁面

      安裝(安裝最新LTS版):

      pip3 install django==1.11.9

      創建一個django項目:

      下面的命令創建了一個名為"mysite"的Django 項目:

      django-admin startproject mysite

      目錄介紹:

      mysite/
      ├── manage.py  # 管理文件
      └── mysite  # 項目目錄
          ├── __init__.py
          ├── settings.py  # 配置
          ├── urls.py  # 路由 --> URL和函數的對應關系
          └── wsgi.py  # runserver命令就使用wsgiref模塊做簡單的web server

      運行Django項目:

      python manage.py runserver 127.0.0.1:8000

      模板文件配置:

      TEMPLATES = [
          {
              'BACKEND': 'django.template.backends.django.DjangoTemplates',
              'DIRS': [os.path.join(BASE_DIR, "template")],  # template文件夾位置
              'APP_DIRS': True,
              'OPTIONS': {
                  'context_processors': [
                      'django.template.context_processors.debug',
                      'django.template.context_processors.request',
                      'django.contrib.auth.context_processors.auth',
                      'django.contrib.messages.context_processors.messages',
                  ],
              },
          },
      ]

      靜態文件配置:

      STATIC_URL = '/static/'  # HTML中使用的靜態文件夾前綴
      STATICFILES_DIRS = [
          os.path.join(BASE_DIR, "static"),  # 靜態文件存放位置
      ]

       剛開始學習時可在配置文件中暫時禁用csrf中間件,方便表單提交測試。

      MIDDLEWARE = [
          'django.middleware.security.SecurityMiddleware',
          'django.contrib.sessions.middleware.SessionMiddleware',
          'django.middleware.common.CommonMiddleware',
          # 'django.middleware.csrf.CsrfViewMiddleware',
          'django.contrib.auth.middleware.AuthenticationMiddleware',
          'django.contrib.messages.middleware.MessageMiddleware',
          'django.middleware.clickjacking.XFrameOptionsMiddleware',
      ]

      四、Django基礎三件套

      from django.shortcuts import HttpResponse, render, redirect

      HttpResponse

      內部傳入一個字符串參數,返回給瀏覽器。

      例如:

      def index(request):
          # 業務邏輯代碼
          return HttpResponse("OK")

      render

      除request參數外還接受一個待渲染的模板文件和一個保存具體數據的字典參數。

      將數據填充進模板文件,最后把結果返回給瀏覽器。(類似于我們上面用到的jinja2)

      例如:

      def index(request):
          # 業務邏輯代碼
          return render(request, "index.html", {"name": "alex", "hobby": ["燙頭", "泡吧"]})

      redirect

      接受一個URL參數,表示跳轉到指定的URL。

      例如:

      def index(request):
          # 業務邏輯代碼
          return redirect("/home/")

      五、重定向是怎么回事?

       

      posted @ 2020-07-19 00:24  Elton丶  閱讀(230)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产美女高潮流白浆视频| 香蕉av777xxx色综合一区| 国产精品无码无片在线观看3d| 国产激情免费视频在线观看| 久久国内精品自在自线观看| 国内精品无码一区二区三区| 婷婷五月综合丁香在线| 亚洲国产一区二区三区最新| 欧美一级黄色影院| 久久精品国产清自在天天线| 亚洲AV永久中文无码精品综合| 亚洲AV无码秘?蜜桃蘑菇| 污污内射在线观看一区二区少妇| 18禁极品一区二区三区| 精品久久人人做爽综合| 亚洲色一色噜一噜噜噜| 国产大尺度一区二区视频| 人人妻人人澡人人爽欧美一区双 | 91中文字幕在线一区| 国产卡一卡二卡三免费入口| 视频一区视频二区在线视频| 无码日韩精品一区二区三区免费| 伊人成人在线视频免费| 国产精品久久久国产盗摄| 国产一区国产二区在线视频 | 成人伊人青草久久综合网| 图片区偷拍区小说区五月 | 亚洲中文久久久久久精品国产| 亚洲成av人片乱码色午夜| 中文国产不卡一区二区| 人人人澡人人肉久久精品| 91蜜臀国产自产在线观看| 精品亚洲欧美高清不卡高清| 亚洲成人av在线系列| 鹤壁市| 五月天丁香婷婷亚洲欧洲国产| 国产中文字幕精品在线| 国产不卡一区二区精品| 亚洲成在人天堂一区二区| jk白丝喷浆| 人妻少妇偷人精品视频|