Flask基本介紹及使用

01.基本介紹及使用

 

文章目錄

 

1、介紹

1.web框架

  • 可以被服務器調用起來,根據客戶端請求的執行不一樣的邏輯處理造成要返回數據的程序
  • **核心:**實現路由和視圖(業務邏輯處理)

2.框架的輕重

  • 重量級的框架:爲方便業務開發,提供了豐富的工具、組件例如Django。
  • 輕量級的框架:只提供web框架的核心功能,自由,靈活,高度定製。如flask、Tornado。

三大主流框架:

  • django:大而全,重武器,內部提供:ORM、Admin、ModelForm,Session,緩存,型號,CSRF。
  • Flask:短小精悍,可擴展性強,第三方組件豐富
  • tornado:短小精悍,異步非阻塞

其餘:html

  • web.py
  • bottle.py

3.Flask簡介

Flask誕生於2010年,是Armin ronacher(人名)用 Python 語言基於 Werkzeug 工具箱編寫的輕量級Web開發框架。前端

Flask 自己至關於一個內核,其餘幾乎全部的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login,數據庫Flask-SQLAlchemy),都須要用第三方的擴展來實現。好比能夠用 Flask 擴展加入ORM、窗體驗證工具,文件上傳、身份驗證等。Flask 沒有默認使用的數據庫,你能夠選擇 MySQL,也能夠用 NoSQL。python

其 WSGI 工具箱採用 Werkzeug(路由模塊),模板引擎則使用 Jinja2。這兩個也是 Flask 框架的核心。mysql

官方 官方文檔(中文)web

4.與django對比

django提供了:正則表達式

  • django-admin快速建立項目工程
  • manage.py管理項目工程
  • ORM模型(數據庫抽象層)
  • admin後臺管理站點
  • 緩存機制
  • 文件存儲系統
  • 用戶認證系統

而這些,flask都沒有,都須要擴展包來提供。sql

3.Flask經常使用第三方擴展包:

Flask-SQLalchemy:操做數據庫,ORM. 號稱操做數據庫最快的框架SQLalchemy;數據庫

Flask-script:終端腳本工具,腳手架;django

Flask-migrate:管理遷移數據庫. 比Django的更增強大, 遷移數據的過程當中還能夠回滾;json

Flask-Session:Session存儲方式指定;

Flask-WTF:表單;

Flask-Mail:郵件;

Flask-Bable:提供國際化和本地化支持,翻譯;
Flask-Login:認證用戶狀態;

Flask-OpenID:認證, OAuth;

Flask-RESTful:開發REST API的工具;

Flask JSON-RPC: 開發rpc遠程服務[過程]調用

Flask-Bootstrap:集成前端Twitter Bootstrap框架

Flask-Moment:本地化日期和時間

Flask-Admin:簡單而可擴展的管理接口的框架

能夠經過 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推薦的擴展

2、基本使用

1.安裝

pip install flask

2.儲備知識 werkzeug

依賴 wsgi werkzeug

介紹: Werkzeug是一個WSGI工具包,他能夠做爲一個Web框架的底層庫。

補充: werkzeug 不是一個web服務器,也不是一個web框架,而是一個工具包,官方的介紹說是一個 WSGI 工具包,它能夠做爲一個 Web 框架的底層庫,由於它封裝好了不少 Web 框架的東西,例如 Request,Response 等等

示例一:

from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

示例二:

from werkzeug.wrappers import Request, Response

class Flask(object):
    def __call__(self.serving,run_simple)
    	return '請求來了'
if __name__== 'main':
    run_simple('localhost', 4000, hello)

示例三:

from werkzeug.wrappers import Request, Response

class Flask(object):
    def __call__(self.serving,self):
    	return '請求來了'
    def run(self):
        run_simple('127.0.0.1',5000,self)
app =Flask()
if __name__== 'main':
    app.run()

3.pycharm建立flask項目

與django不一樣,flask不會提供任何的自動操做,因此須要手動建立項目目錄,須要手動建立啓動項目的管理文件

例如,建立項目目錄 flaskdemo,在目錄中建立manage.py.在pycharm中打開項目並指定上面建立的虛擬環境

image-20210603174726049

4.建立flask框架主程序

名字可隨便更改,能夠是app.py/run.py/main.py/index.py

from flask import Flask

# 建立flask的應用對象
# __name__表示當前模塊的名字
#           模塊名,Flask這個模塊所在的目錄爲總目錄,默認這個目錄中的static爲靜態目錄,templates爲模板目錄
app = Flask(__name__)


# @app.route('/')
def hello_world():
    '''定義的視圖函數'''
    return 'Hello World!'

if __name__ == '__main__':
    # 注意:flask默認端口5000
    app.run()

5.代碼分析

# 導入Flask類
from flask import Flask

"""
import_name      Flask程序所在的包(模塊),傳 __name__ 就能夠
                 其能夠決定 Flask 在訪問靜態文件時查找的路徑
static_path      靜態文件訪問路徑(不推薦使用,使用 static_url_path 代替)
static_url_path  靜態文件訪問路徑,能夠不傳,默認爲:/ + static_folder
static_folder    靜態文件存儲的文件夾,能夠不傳,默認爲 static
template_folder  模板文件存儲的文件夾,能夠不傳,默認爲 templates
"""
app = Flask(import_name=__name__)


# 編寫路由視圖
# flask的路由是經過給視圖添加裝飾器的方式進行編寫的。固然也能夠分離到另外一個文件中。
# flask的視圖函數,flask中默認容許經過return返回html格式數據給客戶端。
@app.route(rule='/')
def index():
    return '<mark>Hello Word!</make>'

# 加載項目配置
class Config(object):
    # 開啓調試模式
    DEBUG = True

# flask中支持多種配置方式,經過app.config來進行加載,咱們會這裏經常使用的是配置類
app.config.from_object( Config )


# 指定服務器IP和端口
if __name__ == '__main__':
    # 運行flask
    app.run(host="0.0.0.0", port=5000)

小結:

  • Flask框架基於werkzeug的wsgi實現,flask本身沒有wsgi
  • 用戶一旦請求來了,就會執行__call__方法
  • 寫Flask標準流程
    1. 建立一個Flask對象
    2. 將路由和視圖放在一塊兒,能夠寫多個
    3. 在調用app.run()本質是內部調用了werkzeug

6.案例:登陸、顯示用戶信息

main.py

from flask import Flask,render_template,request,redirect,session,url_for
app = Flask(__name__)
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'

USERS = {
    1:{'name':'張三','age':18,'gender':'男','text':"道路千萬條"},
    2:{'name':'李四','age':28,'gender':'男','text':"搞錢第一條"},
    3:{'name':'王五','age':18,'gender':'女','text':"行車不規範"},
}

@app.route('/detail/<int:nid>',methods=['GET'])
def detail(nid):
    user = session.get('user_info')
    if not user:
        return redirect('/login')

    info = USERS.get(nid)
    return render_template('detail.html',info=info)


@app.route('/index',methods=['GET'])
def index():
    user = session.get('user_info')
    if not user:
        # return redirect('/login')
        url = url_for('l1')
        return redirect(url)
    return render_template('index.html',user_dict=USERS)


@app.route('/login',methods=['GET','POST'],endpoint='l1')
def login():
    if request.method == "GET":
        return render_template('login.html')
    else:
        # request.query_string
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'lqz' and pwd == '123':
            session['user_info'] = user
            return redirect('http://www.baidu.com')
        return render_template('login.html',error='用戶名或密碼錯誤')

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

detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>詳細信息 {{info.name}}</h1>
    <div>
        {{info.text}}
    </div>
</body>
</html>

index.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用戶列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看詳細</a></td>        </tr>        {% endfor %}    </table></body></html>

login.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用戶登陸</h1>    <form method="post">        <input type="text" name="user">        <input type="text" name="pwd">        <input type="submit" value="登陸"><span style="color:red">{{error}}</span>    </form></body></html>

小總結:

  1. flask路由

    @app.route('/login')def login():    pass
  2. 路由的參數

    @app.route('/login',methods=['GET','POST'],endpoint='l1')def login():    pass'''第一個參數:url第二個參數:支持的請求方法第三個參數:endpoint反向解析,不寫默認爲函數名,而且不能重名,重名就報錯'''
  3. 動態路由

    @app.route('/index')def login():    pass@app.route('/index/<name>')def index(name):    pass@app.route('/index/int:<nid>')def index(nid):    pass
  4. 獲取提交的數據

    from flask import request@app.route('/index')def login():    request.args # GET請求傳遞的參數    request.form # POST請求傳遞的參數
  5. 返回數據

    @app.route('/index')def login():    return render_template('模板文件')	return jsonify(...)	# 傳遞json格式的數據	return redirect('/index/') # 傳遞url	return redirect(url_for('別名'))	# 別名	return '字符串'
  6. 模板處理

    {{值}}{%for item in list %}	{{item}}{% endfor %}{# #}  #註釋

3、配置文件

1.默認配置

flask中的配置文件是一個flask.config.Config對象(繼承字典),默認配置爲:

{        'DEBUG':                                get_debug_flag(default=False),  是否開啓Debug模式        'TESTING':                              False,                          是否開啓測試模式        'PROPAGATE_EXCEPTIONS':                 None,                                  'PRESERVE_CONTEXT_ON_EXCEPTION':        None,        'SECRET_KEY':                           None,        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),        'USE_X_SENDFILE':                       False,        'LOGGER_NAME':                          None,        'LOGGER_HANDLER_POLICY':               'always',        'SERVER_NAME':                          None,        'APPLICATION_ROOT':                     None,        '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,        'MAX_CONTENT_LENGTH':                   None,        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),        'TRAP_BAD_REQUEST_ERRORS':              False,        'TRAP_HTTP_EXCEPTIONS':                 False,        'EXPLAIN_TEMPLATE_LOADING':             False,        'PREFERRED_URL_SCHEME':                 'http',        'JSON_AS_ASCII':                        True,        'JSON_SORT_KEYS':                       True,        'JSONIFY_PRETTYPRINT_REGULAR':          True,        'JSONIFY_MIMETYPE':                     'application/json',        'TEMPLATES_AUTO_RELOAD':                None,    }

2.多種配置方式

方式一:

app.config['DEBUG'] = TruePS: 因爲Config對象本質上是字典,因此還可使用app.config.update(...)

方式二:

#經過py文件配置app.config.from_pyfile("python文件名稱")如:settings.pyDEBUG = Trueapp.config.from_pyfile("settings.py")#經過環境變量配置app.config.from_envvar("環境變量名稱")#app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])環境變量的值爲python文件名稱名稱,內部調用from_pyfile方法app.config.from_json("json文件名稱")JSON文件名稱,必須是json格式,由於內部會執行json.loadsapp.config.from_mapping({'DEBUG': True})字典格式app.config.from_object("python類或類的路徑")

settings.py(用的最多)

app.config.from_object('pro_flask.settings.TestingConfig')class Config(object):    DEBUG = False    TESTING = False    DATABASE_URI = 'sqlite://:memory:'class ProductionConfig(Config):    DATABASE_URI = 'mysql://user@localhost/foo'class DevelopmentConfig(Config):    DEBUG = Trueclass TestingConfig(Config):    TESTING = TruePS: 從sys.path中已經存在路徑開始寫PS: settings.py文件默認路徑要放在程序root_path目錄,若是instance_relative_config爲True,則就是instance_path目錄(Flask對象init方法的參數)

4、路由系統

1.路由的基本定義

  • 注意:路由和視圖的名稱必須全局惟一,不能出現重複,不然報錯。
# 指定訪問路徑爲 demo@app.route(rule='/demo')def demo():    return "demo"

2.典型寫法

@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')

3.路由參數接收

  • 提示:路由參數就是url路徑的一部分。

3.1任意路由參數接收

# 不限定類型的路由參數傳遞@app.route(rule='/user/<id>')def user(id):  # 接受參數    return "id=%s的用戶中心" % id# 路由參數理論上能夠存在多個# 參數名建議不要使用單字母,由於有些單字母在框架中默認被佔用了。@app.route(rule='/user1/<id>/<page>')def user1(id, page):  # 接受參數    return "id=%s,page=%s" % (id, page)

3.2 限定路由參數接收:轉換器

系統自帶的轉換器具體使用方式在每種轉換器的註釋代碼中有寫,請留意每種轉換器初始化的參數。

轉換器名稱 描述
string 默認類型,接受不帶斜槓的任何文本
int 接受正整數
float 接受正浮點值
path 接收string但也接受斜線
uuid 接受UUID(通用惟一識別碼)字符串 xxxx-xxxx-xxxxx-xxxxx
# 限定類型的路由參數傳遞
# 路由格式:<類型:參數名>
# 路由參數的類型,flask支持 int整型,float浮點數,path路徑,uuid惟一識別碼
@app.route(rule='/user2/<int:id>')
def user2(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'int'> 1
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user3/<string:id>')
def user3(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'str'> zcdsb123
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user4/<float:id>')
def user4(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'float'> 1.1
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user5/<path:id>')
def user5(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'str'> lxdsb/zcdsb
    return f'<mark>Hello {id}!</make>'


@app.route(rule='/user6/<uuid:id>')
def user6(id):
    print('type(id), id:', type(id), id)  # type(id), id: <class 'uuid.UUID'> 95db2e6c-e7a7-11ea-9ca3-48ba4e4e6384
    return f'<mark>Hello {id}!</make>'

3.3 默認轉換器配置

限定路由參數的類型,flask系統自帶轉換器編寫在werkzeug.routing.py文件中。底部能夠看到如下字典:

DEFAULT_CONVERTERS = {   "default": UnicodeConverter,   "string": UnicodeConverter,   "any": AnyConverter,   "path": PathConverter,   "int": IntegerConverter,   "float": FloatConverter,   "uuid": UUIDConverter,}

4.路由系統本質

  • Flask 路由基於裝飾器
  • 裝飾器的執行過程:不加括號的狀況下,把裝飾器下面的函數傳給裝飾器(函數)執行,獲得結果,再賦值給下面的函數
  • Flask路由本質就是app.add_url_rule()
"""1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')    def route(self, rule, **options):        # app對象        # rule= /        # options = {methods=['GET','POST'],endpoint='n1'}        def decorator(f):            endpoint = options.pop('endpoint', None)            self.add_url_rule(rule, endpoint, f, **options)            return f        return decorator2. @decorator    decorator(index)"""#同理def login():    return '登陸'app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"])#與django路由相似#django與flask路由:flask路由基於裝飾器,本質是基於:add_url_rule#add_url_rule 源碼中,endpoint若是爲空,endpoint = _endpoint_from_view_func(view_func),最終取view_func.__name__(函數名)

簡單示例:

from flask import Flaskapp = Flask(__name__)app.config['DEBUG'] = Falsedef index():    return 'index'# Flask路由本質就是`app.add_url_rule()`app.add_url_rule('/', endpoint='index', view_func=index)if __name__ == '__main__':    app.run()

5.app.add_url_rule參數介紹

# 提示: 便是@app.route的參數, 本質也是app.add_url_rule的參數rule='/index'          # 符合URL規則的路由view_func=index        # 視圖函數名稱defaults=None          # 當URL中無參數,函數須要參數時,使用defaults = {'k': 'v'}能夠爲函數提供默認參數endpoint=None          # 名稱,用於反向生成URL,即: url_for('名稱')methods=None           # 容許的請求方式,如:["GET", "post"] 大小寫均可以, 內部會執行upper()strict_slashes=None    # 對URL最後的 / 符號是否嚴格要求, 默認嚴格. False就是不嚴格    @app.route('/index', strict_slashes=False)    # 訪問 http://www.xx.com/index/ 或 http://www.xx.com/index 的路由格式均可以        @app.route('/index', strict_slashes=True)    # 僅支持這種路由格式訪問: http://www.xx.com/index    redirect_to = None      # 重定向到指定地址    @app.route('/index/<int:nid>', redirect_to='/home/<nid>')    subdomain = None        # 子域名訪問    # C:\Windows\System32\drivers\etc\hosts    127.0.0.1       www.liuqingzheng.com    127.0.0.1       admin.liuqingzheng.com    127.0.0.1       buy.liuqingzheng.com        # 示例    from flask import Flask, views, url_for        app = Flask(import_name=__name__)    app.config['SERVER_NAME'] = 'liuqingzheng.com:5000'        @app.route("/", subdomain="admin")    def static_index():        return "static.your-domain.tld"            # 能夠傳入任意的字符串,如傳入的字符串爲aa,顯示爲 aa.liuqingzheng.com    @app.route("/dynamic", subdomain="<username>")    def username_index(username):        return username + ".your-domain.tld"            if __name__ == '__main__':        app.run()            # 支持訪問的路由須要包含以下的域名訪問格式:www dynamic admin    http://www.liuqingzheng.com:5000/dynamic    http://admin.liuqingzheng.com:5000/dynamic    http://buy.liuqingzheng.com:5000/dynamic

6.路由支持正則: 自定義轉換器

基本步驟:

  1. 導入轉換器基類:在Flask中,全部的路由的匹配規則都是使用轉換器對象進行記錄
  2. 寫一個自定義轉換器:自定義類繼承與轉換器基類
  3. 註冊:添加轉換器到默認的轉換器字典中
  4. 使用自定義轉換器實現自定義匹配規則

6.1GL模式

from flask import Flask, request# 初始化app = Flask(import_name=__name__)# 編寫路由視圖@app.route(rule='/')def index():    return "<h1>hello world!</h1>"# 關於路由參數的限制,flask內置的類型不夠具體,在開發中,咱們常常接受參數,須要更加精確的限制# 這時候,可使用正則匹配路由參數# 正則匹配路由參數,其實就是擴展flask內置的路由限定類型,須要完成4個步驟# 1. 引入flask的路由轉換器from werkzeug.routing import BaseConverter# 2. 建立自定義路由轉換器class MobileConverter(BaseConverter):    """手機號碼類型限制"""    def __init__(self, map, *args):        super().__init__(map)        self.regex = "1[3-9]\d{9}"# 3. 把自定義轉換器添加到flask默認的轉換器字典中,也就是和原來的int,float等放在一塊app.url_map.converters['mob'] = MobileConverter# 4. 相似原來的路由參數限制同樣,調用自定義轉換器名稱便可@app.route(rule='/user/<mob:mobile>')def user(mobile):    return mobile# 1. 引入flask的路由轉換器from werkzeug.routing import BaseConverter# 2. 建立自定義路由轉換器class RegexConverter(BaseConverter):    """根據正則進行參數限制"""    def __init__(self, map, *args):        super().__init__(map)        self.regex = args[0]  # args=(\w+@\w+\.\w+, )# 3. 把自定義轉換器添加到flask默認的轉換器字典中,也就是和原來的int,float等放在一塊app.url_map.converters['re'] = RegexConverter# 4. 相似原來的路由參數限制同樣,調用自定義轉換器名稱便可@app.route(rule='/user/<re("\w+@\w+\.\w+"):email>')def user2(email):    print(app.url_map)  # 獲取全部的路由列表    return email# 聲明和加載配置class Config():    DEBUG = Trueapp.config.from_object(Config)if __name__ == '__main__':    # 運行flask    app.run(port=8000)

6.2 LQZ 模式

# 流程: 
"""
1. 寫類,繼承BaseConverter
2. 註冊:app.url_map.converters['regex'] = RegexConverter
3. 使用:@app.route('/index/<regex("\d+"):nid>')  正則表達式會看成第二個參數傳遞到類中
"""

from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter

app = Flask(import_name=__name__)


class RegexConverter(BaseConverter):
    """
    自定義URL匹配正則表達式
    """

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

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

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


# 添加到flask中
app.url_map.converters['regex'] = RegexConverter


@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'


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

5、CBV源碼分析

django中的三件套:
			Httpresponse   ''
			render         render_template
			redirect       redirect
			JsonResponse   jsonify


def auth(func):
    def inner(*args, **kwargs):
        print('before')
        result = func(*args, **kwargs)
        print('after')
        return result

    return inner

class IndexView(views.View):
    methods = ['GET']
    decorators = [auth, ]

    def dispatch_request(self):
        print('Index')
        return 'Index!'

app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
#或者,一般用此方式
  class IndexView(views.MethodView):
            methods = ['GET']
            decorators = [auth, ]

            def get(self):
                return 'Index.GET'

            def post(self):
                return 'Index.POST'
        app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint

6、模板

1.渲染變量

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用戶列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看詳細</a></td>        </tr>        {% endfor %}    </table></body></html>

2.變量的循環

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <h1>用戶列表</h1>    <table>        {% for k,v in user_dict.items() %}        <tr>            <td>{{k}}</td>            <td>{{v.name}}</td>            <td>{{v['name']}}</td>            <td>{{v.get('name')}}</td>            <td><a href="/detail/{{k}}">查看詳細</a></td>        </tr>        {% endfor %}    </table></body></html>

3.邏輯判斷

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用戶列表</h1>
    <table>
        {% if name %}
          <h1>Hello {{ name }}!</h1>
        {% else %}
          <h1>Hello World!</h1>
        {% endif %}
    </table>
</body>
</html>

4.處理XSS***

app.py

from flask import Flask, Markup, render_template

app = Flask(__name__)


def func1(arg):
    # Markup 相似於 Django中的make_save
    return Markup("<input type='text' value='%s' />" % (arg,))


@app.route('/')
def index():
    return render_template('xss.html', ff=func1)


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

xss.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ff('六五')}}
    <!-- safe和Django中過濾器中的safe方法一致 -->
	{{ff('六五')|safe}}
</body>
</html>

注意:

  1. Markup等價django的mark_safe ,

  2. extends,include如出一轍

7、請求與響應對象

from flask import Flask, request, jsonify, make_response

app = Flask(__name__)
app.debug = True


@app.route('/', methods=['GET', 'POST'])
def index():
    from werkzeug.datastructures import CombinedMultiDict
    # --------------------------- 請求對象 ---------------------------
    # 獲取當前請求方法
    print(request.method)  # POST

    # 獲取get請求提交的數據
    print(request.args)  # ImmutableMultiDict([('name', 'yang'), ('age', '18')])
    print(type(request.args))  # <class 'werkzeug.datastructures.ImmutableMultiDict'>
    print(request.args.get('name'))  # yang
    from werkzeug.datastructures import ImmutableMultiDict

    # 獲取get形式提交的數據(提示: 須要本身轉)
    print(request.query_string)  # b'name=yang&age=18'

    # 獲取post請求提交的數據
    print(request.form)  # ImmutableMultiDict([('name', 'yang666'), ('age', '22')])

    # 獲取文件
    print(
        request.files)  # ImmutableMultiDict([('avatar', <FileStorage: 'default.jpg' ('image/jpeg')>), ('sql_file', <FileStorage: 'luffyapi.sql' ('application/x-sql')>)])
    print(request.files.get('avatar'))  # FileStorage: 'default.jpg' ('image/jpeg')>

    # 獲取post和get提交的數據總和
    print(
        request.values)  # CombinedMultiDict([ImmutableMultiDict([('name', 'yang'), ('age', '18')]), ImmutableMultiDict([('name', 'yang666'), ('age', '22')])])
    print(request.values.get('name'))  # yang
    print(request.values.get('age'))  # 18
    print(request.values.getlist('name'))  # ['yang', 'yang666']

    # 獲取客戶端所帶的cookie
    print(request.cookies)  # {'key': 'woshicookies', 'user': 'yang'}

    # 獲取請求頭中所攜帶的數據
    print(request.headers)
    '''
    Yang: xiudetianhualuanzui
    Cookie: key=woshicookies; xxx=lqz
    User-Agent: PostmanRuntime/7.26.3
    Accept: */*
    Postman-Token: 40bb7ca6-ba5b-4d1a-9732-1f49cfef954f
    Host: 127.0.0.1:8080
    Accept-Encoding: gzip, deflate, br
    Connection: keep-alive
    Content-Type: multipart/form-data; boundary=--------------------------487226677414449536798986
    Content-Length: 65491
    '''

    # 獲取不帶域名的請求路徑
    print(request.full_path)  # /?name=yang&age=18
    # 獲取不帶域名只帶參數的請求路徑
    print(request.path)  # /

    # 獲取帶域名帶參數的請求路徑
    print(request.url)  # http://127.0.0.1:8080/?name=yang&age=18
    # 獲取帶域名請求路徑
    print(request.base_url)  # http://www.yang1333.com:8080/
    # 獲取域名
    print(request.url_root)  # http://www.yang1333.com:8080/
    # 獲取域名
    print(request.host_url)  # http://www.yang1333.com:8080/
    # 獲取當前請求用戶IP: 127.0.0.1:500
    print(request.host)  # www.yang1333.com:8080

    # --------------------------- 響應對象 ---------------------------
    # 返回三板斧: 字符串, render_template, redirect
    return "字符串"
    return render_template('html模板路徑', **{})
    return redirect('/index.html')

    # 返回JSON格式數據: 相似於Django中的JsonResponse對象
    return jsonify({'k1': 'v1'})

    # 返回response對象
    string = 'hello world'
    response = make_response(string)

    # 設置cookie操做
    response.set_cookie('key', 'value')
    response.delete_cookie('key')

    # 設置響應頭
    response.headers['X-Something'] = 'A value'

    # response是flask.wrappers.Response類型
    print(type(response))
    from flask.wrappers import Response

    return response


if __name__ == '__main__':
    print(app.config)
    app.run(port=8080)
相關文章
相關標籤/搜索