记录一次flask 不写session cookie故障

flask 2.2.3

众所周知,flask可以在response中添加Set-Cookie header来把一个加密过的key:value返还给浏览器,并写入cookie中,在expire之前,后面的请求都会带上这个header。这个功能可以做为一种简单、基础的登录状态验证。

但是,在我对着app.py一顿修改,对着flask源文件一顿猛读和猛注释后,突然发现我的测试代码不给我写session cookie了!怎样测试response里都没有Set-Cookie这个header了!

注意,不是不可以通过response.set_cookie()来添加明文cookie,set_cookie的方法正常,而是不能写这种通过app.secret_key加密过的session cookie了。

因为对框架还不熟悉,当时也不知道具体是哪一步判断写cookie的,更不知道从哪里设置断点,然后就新建项目 下载最新flask 3.0, 使用测试代码

发现正常

但是我记得之前用这个2.2.3也是正常的,于是又在同一个项目写个测试app,发现也正常 。

那么就只有一个可能,当前项目的app代码有bug,导致没有正常写session cookie。

后来就是翻来覆去 的看flask源码,大概明白了http请求到来后的处理流程和调用过程

  1. 大概是从socket上面到达http server,再到wsgi serving
  2.  从wsgi serving到flask层面 app.__call__, flask层面处理view func, 生成response对象,加工response对象(header, code, after_request func, session cookie, cookies等)
  3.  response对象加工完成后,再回调到wsgi serving, 通过start_response把响应结果(body,headers,status)返还给客户端

最后找到判断是否写session cookie的代码 在  app.py 的 process_response()的最后

process_response() 会先被finalize_response()调用, 在try中:

def finalize_request(
    self,
    rv: t.Union[ft.ResponseReturnValue, HTTPException],
    from_error_handler: bool = False,
) -> Response:

    response = self.make_response(rv)    ## 根据各种各样的返回值,加工转换为response对象
    try:
        response = self.process_response(response)     #  生成response对象后,再依次执行after request funcs,再添加cookie
        request_finished.send(self, response=response)   # 发信号
        if not from_error_handler:
            raise
        self.logger.exception(
            "Request finalizing failed with an error while handling an error")
    except Exception as e:
        pass
    return response

# cookie: 在执行完after request函数后,通过save_session处理 是否需要写cookie到response对象中
    def process_response(self, response: Response) -> Response:   ## 倒序 执行所有的after request 函数
        
        ctx = request_ctx._get_current_object()  # type: ignore[attr-defined]  # 从LocalProxy对象返回一个requestcontext对象

        for func in ctx._after_request_functions:
            response = self.ensure_sync(func)(response)

### 倒序执行所有的after_request funcs 
        for name in chain(request.blueprints, (None,)):
            if name in self.after_request_funcs:
                for func in reversed(self.after_request_funcs[name]):
                    response = self.ensure_sync(func)(response)
## 保存session,save保存之前会去判断一次
        if not self.session_interface.is_null_session(ctx.session):
            self.session_interface.save_session(self, ctx.session, response)

        return response

判断的条件在flask/sessions里写,条件很简单,基本就是如果你在视图函数手动编辑过session对象内容, 例如 session['mvp'] = 'jordan' 那么就是 judge = True。

def should_set_cookie(self, app: "Flask", session: SessionMixin) -> bool:
    """ 判断是否需要写session cookie  要在子类中调用
    judge = session.modified or (
        session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
    )
    return judge

但是通过一行一行调试,我发现 我的程序在process_response中,执行完after request funcs的部分后就不往下了,直接返回finalize_response()中的exception部分了,异常信息是 :

此时我就意识到可能是我的after request funcs中某一个忘记把response重新返还了,

去检查,果不其然,有一个本来打算记录日志的函数,return被注释掉了,导致没有返回值,默认就返回None了,然后就被类型检查捕捉到了,然后process_response异常,提前结束,save_session的部分无法执行,也就写不了session cookie了。

主要还是对框架不熟悉,花了巨量时间来阅读源码,添加笔记,debug。坏处是相当费时间,

好处是对框架更熟悉了,对各种模块和实现加深了印象。

BTW  debug第三方框架或者代码时,最好不要用print 否则很可能debug完了 找不到print写在哪里了,想删都删不掉。最好用logger,可以方便找到filename, lineno.

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值