Python之flask總結

来源:https://www.cnblogs.com/mengqingjian/archive/2018/02/18/8452898.html
-Advertisement-
Play Games

一、flask a、Flask是一個基於Python開發並且依賴jinja2模板和Werkzeug WSGI服務的一個微型框架,對於Werkzeug本質是Socket服務端,其用於接收http請求並對請求進行預處理,然後觸發Flask框架,開發人員基於Flask框架提供的功能對請求進行相應的處理,並 ...


一、flask

     a、Flask是一個基於Python開發並且依賴jinja2模板和Werkzeug WSGI服務的一個微型框架,對於Werkzeug本質是Socket服務端,其用於接收http請求並對請求進行預處理,然後觸發Flask框架,開發人員基於Flask框架提供的功能對請求進行相應的處理,並返回給用戶,如果要返回給用戶複雜的內容時,需要藉助jinja2模板來實現對模板的處理,即:將模板和數據進行渲染,將渲染後的字元串返回給用戶瀏覽器

     b、“微”(micro) 並不表示你需要把整個 Web 應用塞進單個 Python 文件(雖然確實可以 ),也不意味著 Flask 在功能上有所欠缺。微框架中的“微”意味著 Flask 旨在保持核心簡單而易於擴展。Flask 不會替你做出太多決策——比如使用何種資料庫。而那些 Flask 所選擇的——比如使用何種模板引擎——則很容易替換。除此之外的一切都由可由你掌握。如此,Flask 可以與您珠聯璧合。

     c、預設情況下,Flask 不包含資料庫抽象層、表單驗證,或是其它任何已有多種庫可以勝任的功能。然而,Flask 支持用擴展來給應用添加這些功能,如同是 Flask 本身實現的一樣。眾多的擴展提供了資料庫集成、表單驗證、上傳處理、各種各樣的開放認證技術等功能。Flask 也許是“微小”的,但它已準備好在需求繁雜的生產環境中投入使用。

二、安裝

      a、安裝:pip3 install flask

三、虛擬環境

      a、安裝: pip3 install virtualenv

      b、# 創建虛擬環境 virtualenv env1

      c、# 進入虛擬環境 Scripts/activate

      d、 # 退出虛擬環境 Scripts/deactivate

四、flask框架

      a、簡介:輕量級框架
                     Django:無socket、中間件、路由系統、視圖(CBV,FBV)、 模板、ORM、cookie、Session、Admin、Form、緩存、信號、序列化....
                     Flask:無socket、中間件(擴展)、路由系統、視圖(CBV)、第三方模板(jinja2)、cookie、Session弱爆了

      b、 什麼是wsgi?
                           Web服務網管介面,協議。

      c、Flask依賴一個實現了WSGI協議的模塊:werkzeug

五、flask

       a、 -依賴於wsgi模塊:wsgiref,werkzeug,wsgi

       b、  -實例化Flask對象

                  -靜態文件首碼  /xxx

                  -靜態文件目錄

                  -模板路徑

        c、 添加路由關係      

                  -將 Rule(url和視圖函數)添加到Flask對象的url_map欄位中

                  -兩種添加路由的方式

        d、request

                 -request.form

                 -request.args 

六、基本使用

from flask import Flask

# 實例化Flask對象
app = Flask(__name__)

# 生成路由關係,並把關係保存到某個地方,app對象的 url_map欄位中
@app.route('/xxxx')  # @decorator
def index():
    return "Index"

# def index():
#     return "Index"
# app.add_url_rule('/xxx', "n1", index)

if __name__ == '__main__':
    # 啟動程式,監聽用戶請求
    # 一旦請求到來,執行 app.__call__方法
    # 封裝用戶請求
    # 進行路由匹配
    app.run()

     a、保存session的數據存到了瀏覽器上,
        - 優點:減輕了服務端的壓力
        - 缺點:不安全

     b、路由系統:  

  • @app.route('/post/<path:path>')
  • @app.route('/login', methods=['GET', 'POST'])
  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')

七、路由系統

     a、  -可傳入參數     

            @app.route('/user/<username>')

            @qpp.route('/post/<int:post_id>',methods=['GET','POST'],endpoint='fff')

     b、反向生成URL:url_for

     c、擴展Flask的路由系統,讓它支持正則:

from flask import Flask,url_for

                app = Flask(__name__)

                # 定義轉換的類
                from werkzeug.routing import BaseConverter
                class RegexConverter(BaseConverter):
                    """
                    自定義URL匹配正則表達式
                    """

                    def __init__(self, map, regex):
                        super(RegexConverter, self).__init__(map)
                        self.regex = regex

                    def to_python(self, value):
                        """
                        路由匹配時,匹配成功後傳遞給視圖函數中參數的值
                        :param value: 
                        :return: 
                        """
                        return int(value)

                    def to_url(self, value):
                        """
                        使用url_for反向生成URL時,傳遞的參數經過該方法處理,返回的值用於生成URL中的參數
                        :param value: 
                        :return: 
                        """
                        val = super(RegexConverter, self).to_url(value)
                        return val

                # 添加到converts中
                app.url_map.converters['xxx'] = RegexConverter

                # 進行使用
                @app.route('/index/<xxx("\d+"):nid>',endpoint='xx')
                def index(nid):
                    url_for('xx',nid=123)
                    return "Index"

                if __name__ == '__main__':
                    app.run()

八、請求響應

from flask import Flask
    from flask import request
    from flask import render_template
    from flask import redirect
    from flask import make_response

    app = Flask(__name__)


    @app.route('/login.html', methods=['GET', "POST"])
    def login():

        # 請求相關信息
        # request.method
        # request.args
        # request.form
        # request.values
        # request.cookies
        # request.headers
        # request.path
        # request.full_path
        # request.script_root
        # request.url
        # request.base_url
        # request.url_root
        # request.host_url
        # request.host
        # request.files
        # obj = request.files['the_file_name']
        # obj.save('/var/www/uploads/' + secure_filename(f.filename))

        # 響應相關信息
        # return "字元串"
        # return render_template('html模板路徑',**{})
        # return redirect('/index.html')

        # response = make_response(render_template('index.html'))
        # response是flask.wrappers.Response類型
        # response.delete_cookie('key')
        # response.set_cookie('key', 'value')
        # response.headers['X-Something'] = 'A value'
        # return response


        return "內容"

    if __name__ == '__main__':
        app.run()

    a、在django中用make_safe而在Flask中用make_response

九、模板語言   

     a、模板的使用

               Flask使用的是Jinja2模板,所以其語法和Django無差別

     b、自定義模板方法

               Flask中自定義模板方法的方式和Bottle相似,創建一個函數並通過參數的形式傳入render_template,

十、session 

      a、 -session是否還有其他方法?

                     -它與字典方法相同

      b、  -session超時時間如何設置:

app.config['SESSION_COOKIE_NAME'] = 'session_lvning'
            """
            'SESSION_COOKIE_NAME':                  'session',
            'SESSION_COOKIE_DOMAIN':                None,
            'SESSION_COOKIE_PATH':                  None,
            'SESSION_COOKIE_HTTPONLY':              True,
            'SESSION_COOKIE_SECURE':                False,
            'SESSION_REFRESH_EACH_REQUEST':         True,
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31)

     c、除請求對象之外,還有一個 session 對象。它允許你在不同請求間存儲特定用戶的信息。它是在 Cookies 的基礎上實現的,並且對 Cookies 進行密鑰簽名要使用會話,你需要設置一個密鑰。

     d、

  • 設置:session['username'] = 'xxx'

  • 刪除:session.pop('username', None)

十一、閃現(flash)

     a、session從在在服務端的一個字典中,session保存的數據取一次,它還是會有。而flash是基於session創建的,flash支持在裡面放值,只要在裡面取值它就會沒有。閃現就是

     b、在session的基礎上,把它的值真實的放在session上,當去它的時候不僅把它的值取走,還把session的東西去掉。

十二、藍圖

     a、藍圖用於為應用提供目錄劃分

    • 藍圖URL首碼:xxx = Blueprint('account', __name__,url_prefix='/xxx')
    • 藍圖子功能變數名稱:xxx = Blueprint('account', __name__,subdomain='admin')
      # 前提需要給配置SERVER_NAME: app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
      # 訪問時:admin.wupeiqi.com:5000/login.html

十三、DBUtils

      a、DBUtils是Python的一個用於實現資料庫連接池的模塊。

      b、連接池的三種模式:

            (1)、第一種模式:

                                 它的缺點:每一次請求反覆創建資料庫的鏈接,鏈接的次數太多

             (2)、第二種模式:

                                 它的缺點:不能支持併發

              (3)、第三種模式:

                                它是基於DBUtils實現資料庫連接池

                                        -為每個線程創建一個鏈接,該線程關閉時,不是真正的關閉,本線程再次調用時,還是使用的最開始的創建的鏈接,知道線程終止,資料庫鏈接才關閉

                                       -創建一個連接池(10個鏈接),為所有線程提供鏈接,使用時來進行獲取,使用完畢時,再次放回到連接池。

       c、DBUtils的應用:

import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
POOL = PooledDB(
    creator=pymysql,  # 使用鏈接資料庫的模塊
    maxconnections=6,  # 連接池允許的最大連接數,0和None表示不限制連接數
    mincached=2,  # 初始化時,鏈接池中至少創建的空閑的鏈接,0表示不創建
    maxcached=5,  # 鏈接池中最多閑置的鏈接,0和None不限制
    maxshared=3,  # 鏈接池中最多共用的鏈接數量,0和None表示全部共用。PS: 無用,因為pymysql和MySQLdb等模塊的 threadsafety都為1,所有值無論設置為多少,_maxcached永遠為0,所以永遠是所有鏈接都共用。
    blocking=True,  # 連接池中如果沒有可用連接後,是否阻塞等待。True,等待;False,不等待然後報錯
    maxusage=None,  # 一個鏈接最多被重覆使用的次數,None表示無限制
    setsession=[],  # 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='pooldb',
    charset='utf8'
)

十四、session

      a、 session和cookie的原理和區別:

               cookie是保存在瀏覽器上的鍵值對
               session是存在服務端的鍵值對(服務端的session就是一個大字典,字典中是隨機字元串)(session與request原理相同)(session原理跟上下文也有關係)

               session依賴於cookie存在

      b、  session流程      

當請求第一次進來,生成隨機字元串
                  -發給用戶cookie
                  -保存到session字典中時
                  它調用stark將隨機字元串和對應的值放到local
                視圖函數
                 -使用時導入用top(它拿的是session)
                     session=LocalProxy(partile(_lookup_req_object,'session '))
               請求處理完畢:
                     記憶體處理完畢後,將session做持久化(session存到資料庫,存到Redis,存到加密的cookie中)

十五、session源碼解析

     a、先執行Flask的__call__方法 ,調用出來wsgi_app,它先做request的上下文做完,請求剛進來到push中,它先處理request將請求相關的數據,然後添加到了local中,

     b、 緊接著處理session(將RequestContext對象(request,session)添加到local中),request(將request信息封裝到Request(environ)對象並複製給requestContext 對                       象),然後獲取cookie中的隨機字元串,檢驗是否有,沒有就生成。根據隨機字元串,獲取服務端session保存的值。把session放到記憶體中,

     c、  執行wsgi_app方法下麵的視圖函數。執行完視圖函數返回到full_dispatch_requesthong ,觸發只執行一次的裝飾器中(觸發Flask信號),

     d、  執行完這個裝飾器,緊接著執行下麵的特殊的裝飾器,如果這些特殊裝飾器沒有返回值,那麼rv=None,如果有返回值,頁面時就顯示這個返回值,

     e、如果沒有返回值,觸發執行那個視圖函數,拿返回值。請求執行完返回後,調用finalize_request,對它的返回值進行封裝。

十六、Flask和Django的區別 

     a、請求相關的數據           

                  -Django:參數

                  -Flask:    基於Local,LocalStark對象

     b、 多個請求進來會不會混淆            

                  -單線程

                  -多線程

                  -協程

                    解決: from greenlet import getcurrent as get_ident

十七、Flask信號

    a、 Flask框架中的信號基於blinker

    b、安裝: pip3 install blinker

    c、十個信號

1. 內置信號
            10個信號:
                2. request_started = _signals.signal('request-started')                # 請求到來前執行
                5. request_finished = _signals.signal('request-finished')              # 請求結束後執行
                 
                3. before_render_template = _signals.signal('before-render-template')  # 模板渲染前執行
                4. template_rendered = _signals.signal('template-rendered')            # 模板渲染後執行
                 
                2/3/4/5或不執行 got_request_exception = _signals.signal('got-request-exception')    # 請求執行出現異常時執行
                 
                6. request_tearing_down = _signals.signal('request-tearing-down')      # 請求執行完畢後自動執行(無論成功與否)
                7. appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 請求上下文執行完畢後自動執行(無論成功與否)
                 
                 
                1. appcontext_pushed = _signals.signal('appcontext-pushed')            # 請求app上下文push時執行
                
                8. appcontext_popped = _signals.signal('appcontext-popped')            # 請求上下文pop時執行
                
                message_flashed = _signals.signal('message-flashed')                   # 調用flask在其中添加數據時,自動觸發

     d、flask信號本生自己沒有,用的是別人的,並且這些信號通過裝飾器全部可以代替了的,但是Django裡面有些特殊的
就是那些model操作根本沒有裝飾器,就是同過內置的信號來完成的

十八、django內置的信號

Request/response signals
                    request_started             # 請求到來前,自動觸發
                    request_finished            # 請求結束後,自動觸發
                    got_request_exception       # 請求異常後,自動觸發
                
                Model signals
                    pre_init                    # django的modal執行其構造方法前,自動觸發
                    post_init                   # django的modal執行其構造方法後,自動觸發
                    
                    pre_save                    # django的modal對象保存前,自動觸發
                    post_save                   # django的modal對象保存後,自動觸發
                    
                    pre_delete                  # django的modal對象刪除前,自動觸發
                    post_delete                 # django的modal對象刪除後,自動觸發
                    
                    m2m_changed                 # django的modal中使用m2m欄位操作第三張表(add,remove,clear)前後,自動觸發
                    
                    class_prepared              # 程式啟動時,檢測已註冊的app中modal類,對於每一個類,自動觸發
                    
                Management signals
                    pre_migrate                 # 執行migrate命令前,自動觸發
                    post_migrate                # 執行migrate命令後,自動觸發
                
                Test signals
                    setting_changed             # 使用test測試修改配置文件時,自動觸發
                    template_rendered           # 使用test測試渲染模板時,自動觸發
                Database Wrappers
                    connection_created          # 創建資料庫連接時,自動觸發

十九、Wtform

    a、WTForms是一個支持多個web框架的form組件,主要用於對用戶請求數據進行驗證。

    b、安裝: pip3 install wtform

    c、用途:

       1、用戶登錄註冊

               當用戶登錄時候,需要對用戶提交的用戶名和密碼進行多種格式校驗。如:

              用戶不能為空;用戶長度必須大於6;

              密碼不能為空;密碼長度必須大於12;密碼必須包含 字母、數字、特殊字元等(自定義正則);

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True


class LoginForm(Form):
    name = simple.StringField(
        label='用戶名',
        validators=[
            validators.DataRequired(message='用戶名不能為空.'),
            validators.Length(min=6, max=18, message='用戶名長度必須大於%(min)d且小於%(max)d')
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'}

    )
    pwd = simple.PasswordField(
        label='密碼',
        validators=[
            validators.DataRequired(message='密碼不能為空.'),
            validators.Length(min=8, message='用戶名長度必須大於%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
                              message='密碼至少8個字元,至少1個大寫字母,1個小寫字母,1個數字和1個特殊字元')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )



@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用戶提交數據通過格式驗證,提交的值為:', form.data)
        else:
            print(form.errors)
        return render_template('login.html', form=form)

if __name__ == '__main__':
    app.run()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登錄</h1>
<form method="post">
    <!--<input type="text" name="name">-->
    <p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p>

    <!--<input type="password" name="pwd">-->
    <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
    <input type="submit" value="提交">
</form>
</body>
</html>
login

二十、SQLALchemy

    a、介紹 :      

           SQLALchemy是一個基於Python實現的ORM框架。該框架是建立在DB API之上,使用關係對象映射進行資料庫操作

           簡言之便就是:將類和對象轉換成SQL,然後使用數據API執行SQL並獲取執行的結果

    b、安裝: pip3 install SQLALchemy

    c、組成部分

 engine,                                     框架的引擎

     Connection  Pooling  ,                      資料庫連接池

     Dialect,                                    選擇鏈接資料庫的DB  API種類

     Schema /Types,                              架構和類型     

     SQL Exprression Language,                   SQL表達式語言

    d、SQLALcheam本省無法操作資料庫,其必須來pymysql等第三方插件, Dialect用於數據API的交流,根據配置文件的不同

調用不同的資料庫API,從而實現對資料庫的操作

MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
    
pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
    
MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
    
cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
    
更多:http://docs.sqlalchemy.org/en/latest/dialects/index.html

 

 

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、List和Set介面繼承自Collection介面,而Map不是繼承的Collection介面 2.、List介面 List介面有三個實現類:LinkedList,ArrayList,Vector LinkedList:底層基於鏈表實現,鏈表記憶體是散亂的,每一個元素存儲本身記憶體地址的同時還存儲下 ...
  • 兩個實體類:客戶與聯繫人,一個客戶可以有多個聯繫人 客戶類: package domain; import java.util.HashSet; import java.util.Set; //客戶實體 public class Customer { private Long cust_id; pr ...
  • 我們以 printf 這個 very 熟悉的函數為例,來分析一下變參函數。先看下 printf 函數的定義: ~~~~ int printf(const char fmt, ...) { int i; int len; / va_list 即 char / va_list args; va_star ...
  • 2、xml配置文件: 3、實例對象: 4、BeanFactory工廠: ...
  • Python urllib urlretrieve函數解析 利用urllib.request.urlretrieve函數下載文件 覺得有用的話,歡迎一起討論相互學習~ "Follow Me" 參考文獻 "Urlretrieve函數解析" urllib.request.urlretrieve函數解析 ...
  • 一、攔截器 1.概述 ​ 在struts2中,攔截器(Interceptor)是用來動態攔截Action執行的對象。 ​ 攔截器有點類似以前Servlet階段的Filter(過濾器) , 能夠在請求到達Action之前進行攔截操作, 可以在裡面進行判斷校驗。 典型的例子: 登錄攔截. 註:過濾器可以 ...
  • 拖了這麼久,最終還是戰勝了懶惰,打開電腦寫了這篇博客,內容也很簡單,python實現字元串轉整型的int方法 python已經實現了int方法,我們為什麼還要再寫一遍,直接用不就好了?事實確實如此,但是int函數看似簡單,實際上自己來實現還是有一些坑的 1.判斷正負 這點很容易忘記 2.python ...
  • HQL查詢:hibernate獨有的查詢語言 適用於不複雜的多表查詢 示例: 實體類: package domain; public class Customer { private Long cust_id; private String cust_name; private String cus ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...