• Flask


    请求响应

    flask的请求信息都在request里

    flask的响应方式有四剑客,也可以自定义响应

    • 请求相关信息

            # request.method  提交的方法
            # request.args  get请求提及的数据  类似字典类型
            # request.form   post请求提交的数据  类似字典类型
            # request.values  post和get提交的数据总和  类似字段类型
            # request.cookies  客户端所带的cookie
            # request.headers  请求头
            # request.path     不带域名,请求路径
            # request.full_path  不带域名,带参数的请求路径
            # request.script_root  
            # request.url           带域名带参数的请求路径
            # request.base_url      带域名请求路径
            # request.url_root      域名
            # request.host_url      域名
            # request.host          127.0.0.1:500
            # 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')
            # return jsonify({'k1':'v1'})
    • 自定义响应

    1 导入make_response
    2 response=make_response(4剑客)
    3 操作response
    4 return response
    from flask import Flask
    from flask import render_template
    from flask import make_response
    
    @app.route('/login.html', methods=['GET', "POST"])
    def login():
        # 实例化响应对象,可以将四剑客传入,
        response = make_response(render_template('login.html'))
        # response是flask.wrappers.Response类型
        response.delete_cookie('key')  # 删除客户端的cookie
        response.set_cookie('key', 'value')  # 在响应对象中添加cookie
        response.headers['X-Something'] = 'A value'  # 在响应对象中设置响应头
        return response

    cookie与session

    在使用session之前必须现在设置一下密钥

    app.secret_key="asdas" #值随便

    在使用session之前必须现在设置一下cookies的键

    app.config['SESSION_COOKIE_NAME']="keys" 

    除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。 (app.session_interface对象)

    设置:session['username'] = 'xxx'
    #在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
    #在flask中他没有数据库,但session是怎样实现的?
        # 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
        #我们通过app.session_interface来查看
      
    
    删除:session.pop('username', None)
    • app.session_interface中save_session的参数(设置cookie的参数)

    key, 键
    value='', 值
    max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是 None`` ,这个cookie会延续到浏览器关闭为止
    expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
    path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
    domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
    secure=False, 浏览器将通过HTTPS来回传cookie
    httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    • session源码的执行流程

    -save_seesion
        -响应的时候,把session中的值加密序列化放大到了cookie中,返回到浏览器中
    -open_session
        -请求来了,从cookie中取出值,反解,生成session对象,以后再视图函数中直接用sessoin就可以了。
    app.session_interface这里面看
    存session,
    1 调用save_session,将我们的session加密的val,读取配置文件['SESSION_COOKIE_NAME']得到key
    2 将1种的key,val存储到cookies

    取session
    1 获取request里面的cookies,获取里面key,这个key就是['SESSION_COOKIE_NAME'],值就是加密的值
    2 对该值进行解密
    from flask import Flask,session
    
    app = Flask(__name__)
    # 设置session秘钥
    app.secret_key="askjdaksd"
    # 用于返回到前端作为cookies的键
    app.config['SESSION_COOKIE_NAME']="cookie_keys"
    
    # app.session_interface
    
    @app.route("/")
    def index():
        session['key']="value"
        return "ok"
    
    @app.route("/index1")
    def index1():
        print(session['key'])
        return "ok"
    
    # 前端cookies中: name是cookie_keys , value是session的key与value加密的字符串

    闪现

    什么是闪现
    a 产生信息,传给 c 页面
    但是用户访问a 页面以后,不是直接跳转到c,而是到b,或则是其他页面,但是用户访问c页面的时候,
    把a产生的信息拿到,这个信息只显示一次,再次访问c页面,信息不再显式
    • 使用

    1.如果要用flash就必须设置app.secret_key
    2.只能取一次,在取就没有了
    
    - 设置: flash('普通信息',category="error")  category 对信息分类
    - 取值: get_flashed_messages(with_categories=True,category_filter=("error",))
        - with_categories 默认为False, 默认获取时不只显示信息,不显示分组
        - category_filter 默认为(), 用来指定获取那个分组的信息
    def flash(message, category="message"):
        flashes = session.get("_flashes", [])
        # flashes = [(category, message),...]
        flashes.append((category, message))
        session["_flashes"] = flashes
        message_flashed.send(
            current_app._get_current_object(), message=message, category=category
        )
    def get_flashed_messages(with_categories=False, category_filter=()):
        flashes = _request_ctx_stack.top.flashes
        if flashes is None:
            _request_ctx_stack.top.flashes = flashes = (
                session.pop("_flashes") if "_flashes" in session else []
            )
        if category_filter:
            flashes = list(filter(lambda f: f[0] in category_filter, flashes))
        if not with_categories:
            return [x[1] for x in flashes]
        return flashes
    flash源码
    from flask import Flask,flash,get_flashed_messages,session
    
    app = Flask(__name__)
    app.secret_key = 'asdfasdf'
    
    @app.route('/index')
    def index():
        #(category="message", message))
        flash('超时错误',category="error")
        flash('普通信息',category="info")
        # 闪现信息是session的形式存储,这也解释了为什么必须设置pp.secret_key
        print(session["_flashes"])  # [('error', '超时错误'), ('info', '普通信息')]
        return "index"
    
    @app.route('/error')
    def error():
        data = get_flashed_messages(with_categories=True,category_filter=("error","info"))
        data1 = get_flashed_messages(with_categories=True, category_filter=("error", "info"))
        print("data1",data1)  # ata1 [('error', '超时错误'), ('info', '普通信息')]
        print("data",data)  # data [('error', '超时错误'), ('info', '普通信息')]
        return "错误信息"
    
    # 在一次请求内,可多次获取闪现信息,当第二向/error请求时,闪现信息为空,
    # 闪现信息是从session.pop取出赋值给flashes,看源码得知,在同一请求内科多次拿到闪现信息
    # 当再次向/error请求时,session内已经没有闪现信息,所以打印出来为空
    if __name__ == '__main__': app.run()

    请求扩展

    • before_request

    类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情

    #基于它做用户登录认证
    @app.before_request
    def process_request(*args,**kwargs):
        if request.path == '/login':
            return None
        user = session.get('user_info')
        if user:
            return None
        return redirect('/login')
    
     # 当时返回值为空或None时,继续向下走,否则直接拦截,并向前端返回return的值
    • after_request

    类比django中间件中的process_response,每一个请求之后绑定一个函数

    @app.after_request
    def after2(response):  # 注意 函数必须传入 response
        print("我是请求之后函数")
        # print(response)  <Response 141 bytes [200 OK]>
        return response  # 注意 函数必须返回 response
    
    @app.route('/test')
    def test():
        print("我是真的视图")
        return render_template("test.html")

    >>>:
    # 我是真的视图
    # 我是请求之后函数2
    # 我是请求之后函数1
    • before_first_request

    第一次请求时,会调用函数,之后不再调用

    @app.before_first_request
    def before_first():
        print("before_first_request")  # 会在视图函数前调用
    • teardown_request

    如论有没有异常都会执行,如果没有异常这个参数就是None,有就记录这个异常

    @app.teardown_request
    def tear(e):
        print('teardown_request')  # 可以用来记录bug日志
        print(e)
    • errorhandler

    路径不存在时404,服务器内部错误500

    # 捕获异常,如果出现异常,而且状态就是@app.errorhandler(404),
    @app.errorhandler(404)
    def error_404(arg):
        print(arg)
        return "404错误了"
    •  template_global

    全局template函数, 在任意html页面都可以调用

    # 全局template函数, 在任意html页面都可以调用
    @app.template_global()
    def sb(a1, a2):
        return a1 + a2
    •  template_filter

    过滤器,可定义对个参数,任意html页面可调用

    @app.template_filter()
    def db(a1, a2, a3):
        print(a1,a2,a3)
        return a1 + a2 + a3

    中间件

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return 'Hello World!'
    # 模拟中间件
    class Md(object):
        def __init__(self,old_wsgi_app):
            self.old_wsgi_app = old_wsgi_app
    
        def __call__(self,  environ, start_response):
            print('开始之前')
            ret = self.old_wsgi_app(environ, start_response)
            print('结束之后')
            return ret
    
    if __name__ == '__main__':
        #1 我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法 
        #2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
        #3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
        #4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
        #把原来的wsgi_app替换为自定义的,
        
        # 源码中 : self.wsgi_app(environ, start_response) 这里的self就是app
        app.wsgi_app = Md(app.wsgi_app)
        app.run()
  • 相关阅读:
    React native的static propTypes
    修改react native 的工程名
    react native的flatList
    react native获取键盘高度
    git reactNativeBle
    rn踩坑记录
    docker学习3-镜像的基本使用
    docker学习2-搭建centos7-python3.6环境
    docker学习1-CentOS 7安装docker环境
    Python3数据库封装
  • 原文地址:https://www.cnblogs.com/waller/p/11844984.html
Copyright © 2020-2023  润新知