首页 > 编程语言 >学习python-flask02

学习python-flask02

时间:2022-12-12 22:11:59浏览次数:84  
标签:学习 python self request flask02 session cookie print app

请求与响应

请求对象

'''
这个request是全局的请求对象。它在哪个视图函数中就是当前视图函数中的request对象并不会乱。
'''
def index():
    print(request.method)	# 提交的方法
    print(request.args) 	# get请求提及的数据
    print(request.args.get('name'))	# 获取get请求里面的数据
    print(request.form)	# post请求提交的数据
    print(request.values)	# post和get提交的数据总和
    print(request.cookies)	# 客户端所带的cookie
    print(request.headers)	# 请求头
    print(request.path)	# 不带域名,就只是请求路径
    print(request.full_path)	# 不带域名,带参数的请求路径
    print('服务端',request.script_root)	# 
    print(request.url)	# 带域名带参数的请求路径
    print(request.base_url)	# 带域名请求路径
    print(request.url_root)	# 域名
    print(request.host_url)	# 域名
    print(request.host)	# 127.0.0.1:500
    print(request.file)		# 请求的文件数据
    # obj = request.files['files']
    # obj.save('./xx.jpg')
    print(request.data) # django的body
    return 'hello'

响应对象

四件套:
	* render_template
    * redirect
    * jsonify
    * 字符串

@app.route('/', methods=['GET', 'POST'])
def index():
    # from .wrappers import Response
    # 1. 写入响应头
    res = 'xxx'
    res = make_response(res)
    # 2. 往 Reesponse的对象中放入响应头
    res.headers['name'] = 'xxc'
    # 3. 写入cookie
    res.set_cookie('xxc', 'xcc') # 设置cookie
    res.delete_cookie('xx') # 删除cookie,这里不是清空cookie而是将时间设置成过期时间。
    

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获取(不是绝对,底层抓包可以获取也可以被覆盖)】
	
    return res

前后端分离和混合(cookie存法)

前后端混合

* res.set_cookie(K, V)
	后端设置cookie, 浏览器会把cookie保存到cookie中。
	本质:后端把cookie放到响应头中,浏览器读到响应头中有cookie会把cookie写入到浏览器中。

前后端分离

* 直接把客户端要存cookie中的数据放到响应体中。
* 前端(浏览器,app,小程序)自己取出放到相应的位置。
	浏览器使用js写入cookie  view_cookie
    app 使用代码写入到某个位置

session的使用和原理

image

session的使用

# 放值  视图函数中
导入全局的session
session['name'] = 'xcc'

# 取值 视图函数中
导入全局的session
print(session['name'])

源码分析

* django 的这一套都在 from django.contrib.sessions.middleware import SeeionMiddleware

* flask 从请求进来到请求走的整个流程
	def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        try:
            try:
                ctx.push() # 它的源码
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except: 
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            ctx.pop(error)
            
            
            
   # ctx.push 的 373行左右	
  		if self.session is None:
            session_interface = self.app.session_interface
            self.session = session_interface.open_session(self.app, self.request)
            if self.session is None:
                self.session = session_interface.make_null_session(self.app)
                
'''	app.session_interfase 
	就是Flask对象中的一个session_interfase对象         '''
* SecureCookieSessionInterface()
* open_session:请求来了,从cookie中取出三段串,反序列化解密放到session中
* save_session:请求走了,把session字典中的值,序列化加密放到cookie中。
    
  # open_session:请求来了执行
	def open_session(self, app, request) :
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        # val 就是取出的三段:eyJhZ2UiOiIxOSIsIm5hbWUiOiJscXoifQ.Y5ac9g.vOomQFqFuaqXWqRQhvSNyc61UIk
        val = request.cookies.get('session')
        if not val:
            return self.session_class()
        max_age = int(app.permanent_session_lifetime.total_seconds())
        try:
            data = s.loads(val, max_age=max_age)
            return self.session_class(data)
        except BadSignature:
            return self.session_class()
  # 请求走了,执行 save_session
	 def save_session(self, app, session, response):
        name = self.get_cookie_name(app)
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        httponly = self.get_cookie_httponly(app)

        if not session:  # 如果视图函数放了,不为空 session['name']='lqz'
            if session.modified:  # 
                response.delete_cookie(
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )

            return

  
        if session.accessed:
            response.vary.add("Cookie")

        if not self.should_set_cookie(app, session):
            return

        expires = self.get_expiration_time(app, session)
        # 序列化---》加密了
        val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
        # 三段:
        response.set_cookie(
            name, # session
            val,  # 三段:
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )

总结:session的执行流程

1. 请求来的时候,会执行 open_session 然后取出 cookie,判断是否为空。如果不为空就把它序列化解密。变成字典然后转到session对象中,然后到视图函数。

2. 请求走的时候,会执行 save_session, 把session转成字典,然后序列化加密到三段字符串最后放到cookie中。

闪现

flash翻译过来叫闪现

作用
访问a页面错了错,重定向到b页面。要在b页面显示a页面的错误信息
在某个请求中放入值,另一个请求取出,取出来后面再取就没有了。
使用方式一:
设置值:
	flash('不好意思,你不能看')
    可以用多次
取值:取出列表
	get_flashed_messages()
使用方式二:
分类设置和获取

设置值:
    flash('qqqq', category='xcc')
    flash('222', category='x2')
    可以用多次
取值:取出列表
	errors = get_flashed_messages(category_filter=['xcc'])
    
# django 中有同样使用的方式,message框架。

请求扩展

在请求进入视图函数之前,执行一些代码。请求出了视图函数以后又会执行一些代码。类似于django的中间件完成的功能。

这里类似于django的6个中间件的7个装饰器。

1.before_request:

* 在请求进视图函数之前执行。
* 如果是多个相同的话,就会从上往下依次执行。
	类似于django:process_request
* 如果返回四件套之一就可以直接返回了。
	在这里,正常使用request对象。

2. after_request:

* 在请求从视图函数走之后执行。
* 如果是多个相同的话,就会从上往下依次执行。
	类似于django:process_response
* 必须有参数和返回值,参数就是response对象,返回值也必须是response对象。
	session、request 照常使用。
    响应头写什么东西?向cookie中写东西。

3.before_first_request:

* 项目启动后,第一次访问会执行,以后再也不执行了
* 可以做一些初始化的操作。

4.teardown_request:

* 每一个请求之后绑定一个函数,即使遇到了异常。
* 每个请求走,都会执行,记录错误日志
    @app.teardown_request
    def tear_down(e):
        print(e)	# 如果有异常,这是异常对象。
        print('我执行了')

5.errorhandler

* 路径不存在时404,服务器内部错误500
    @app.errorhandler(404)
    def error_404(arg):
        print('404会执行我')
        # return "404错误"
        return render_template('404.html')

    @app.errorhandler(500)	# debug为False情况下才能看到。
    def error_500(arg):
        print('500会执行我')
        return "服务器内部错误"

6.template_global

* 标签,在模板中使用	{{sb(1,2)}}

    @app.template_global()
    def sb(a1, a2):
        return a1 + a2

7.template_filter

* 过滤器,在模板中使用	{{10|db(1,2)}}
    @app.template_filter():
    def db(a1, a2, a3):
        return a1 + a2 + a3

蓝图

blueprint

* 对目录进行划分,因为之前所有的代码都写在一个py文件中,后期会分到多个文件中。
* 蓝图就是为了划分目录的
使用步骤
1. 在不同的view的py中国定义蓝图
2. 使用app对象,注册蓝图
3. 使用蓝图,注册路由,注册请求扩展
1.不用蓝图划分目录
目录结构:
	flask_blueprint
    	-static		# 静态文件存放位置
        -templates	# 模板存放位置
        	-user.html	# 用户html页面
        -views		# 视图函数的py文件
        	-__init__.py	# 里面定义了Flask的app对象
            -goods.py	# 商品相关视图
            -user.py	# 用户相关视图
        -app.py		# 启动文件

2.蓝图小型项目

flask_blueprint_little	# 项目名
	-src				# 项目代码所在路径
    	-__init__.py	# app对象创建的地方
        -templates		# 模板
        	-user.html	# 用户html页面
        -static			# 静态文件
        -views			# 视图函数存放的位置
        	-user.py	# 用户相关视图
            -order.py	# 订单相关视图
    -manage.py	# 启动文件

3.大型项目

flask_blueprint_big			# 项目名
	-src   # 项目代码所在位置
    	-__init__.py # src的init,falsk,app实例化
        -settings.py # 配置文件
    	-admin       # 类似于django的admin app
        	-__init__.py # 蓝图初始化
        	-template   # 模板
            	-backend.html
            -static   # 静态文件
            	-xx.jpg
            -views.py  # 视图层
            -models.py # models层,后期咱们表模型
    	 -api
        	-__init__.py
            -template
			-static
			-models.py
            -views.py
	-manage.py  # 启动文件
	

image

回顾及补充

老刘博客

flask与django

1. flask是一个微小web框架,整个服务可以放在一个文件中,也可以做成很大的项目,需要借助第三方。
	* django内置有很多:后台管理、用户和权限管理、session、缓存、消息框架、自定义命令、orm等
    * flask只留了基本请求和响应处理。

wsgi协议

2. wsgi协议:Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI),是为Python语言定义的Web服务器和Web应用程序或框架之间一种简单而通用的接口。

	* 用django部署路飞的项目:使用uwsgi协议跑在8888端口号,不接受http协议,需要将http协议转成uwsgi协议来访问8888获取后端数据。则用浏览器直接访问8888是与问题的,所以用nginx代理访问8080端口号来获取静态页面。
    
	* wsgi server (比如uWSGI) 要和 wsgi application(比如django )交互,uwsgi需要将过来的请求转给django 处理,那么uWSGI 和 django的交互和调用就需要一个统一的规范,这个规范就是WSGI WSGI(Web Server Gateway Interface)

image

WSGI协议

3. WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。

	* 这是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。

	* 一句话总结: 为Python定义的web服务器和web框架之间的接口标准
    
    * 测试阶段:使用wsgiref运行django,监听的就是http协议,浏览器是可以直接访问的。
    * 使用socket写服务端,有线程,没有任何协议。
    * wsgiref写服务端,是自己写的框架,django测试阶段基于它写的。
    * wekzeug写服务端,flask基于它写的。
    

image

uwsgi协议

4. 它是uWSGI服务器实现的独有的的协议,用于定义传输信息的类型,用于前端你服务器与uWSGI的通信规范。
	* uWSGI是web服务器等同于wsgiref。
    * uwsgi就是uWSGI独有的协议。

image

web框架的性能取决于?

老刘知乎

取决于web服务器的性能。通过上线的进程线程能看出web服务器的性能如何。

异步框架 FastAPi

async def index():
    print('sdfasd')
    a++
    await xxx  # io操作
async def goods():   
    pass


'''
之前的web框架,在开启进程和线程后,一条线程会运行多个携程函数,当协程函数中遇到io就是函数代码中读到await关键字就或切走到其他的协程函数。
'''
协程的作用:gevent是用户态的“线程”也就是协程,单线程下实现并发。
		好处就是无需等待io操作,当发生io调用就是切换到另一个运行的协程上面。充分利用CPU资源。同时gevent通过monkey path(猴子补丁)替换掉标准库中阻塞的模块。
    协程就是让操作系统认为没有io操作,其实就是协程切换到另一个协程上面了。

一旦使用了异步,则以后所有的模块都是异步的。

pymysql	同步的
redis	同步
aiomysql	异步
aioredis	异步

注意:
* 在fastapi或sanic中,要操作mysql、redis要使用异步框架,不然效率会很低。
* 在django 3.x 以后支持异步 以 async为关键字。
但是没有一个特别好的异步orm框架适合django使用异步。
* sqlalchemy正在做,
* tortoise-orm:https://tortoise-orm.readthedocs.io/en/latest/index.html
----------------------------------------------------------  
----------------------------------------------------------
# aiomysql
import asyncio
import aiomysql

loop = asyncio.get_event_loop()

async def test_example():
    conn = await aiomysql.connect(host='127.0.0.1', port=3306,
                                       user='root', password='', db='mysql',
                                       loop=loop)

    cur = await conn.cursor()
    await cur.execute("SELECT Host,User FROM user")
    print(cur.description)
    r = await cur.fetchall()
    print(r)
    await cur.close()
    conn.close()

loop.run_until_complete(test_example())


# aioredis
import aioredis
import asyncio
class Redis:
    _redis = None
    async def get_redis_pool(self, *args, **kwargs):
        if not self._redis:
            self._redis = await aioredis.create_redis_pool(*args, **kwargs)
        return self._redis

    async def close(self):
        if self._redis:
            self._redis.close()
            await self._redis.wait_closed()


async def get_value(key):
    redis = Redis()
    r = await redis.get_redis_pool(('127.0.0.1', 6379), db=7, encoding='utf-8')
    value = await r.get(key)
    print(f'{key!r}: {value!r}')
    await redis.close()         

if __name__ == '__main__':
    asyncio.run(get_value('key'))  # need python3.7    

image

* 同步框架在线程中遇到io就会释放GIL锁,这个线程就不执行
		conn = pymysql.conn()
* 异步框在线程中遇到io就不会释放GIL锁,这个线程还是能继续执行。
		await conn = aiomysql.conn()
    
* 同步框架回释放GIL锁导致该线程阻塞
* 异步框架会使用await关键字就不会释放GIL锁会继续执行其他协程函数。

标签:学习,python,self,request,flask02,session,cookie,print,app
From: https://www.cnblogs.com/bjyxxc/p/16977253.html

相关文章