ragflow后端解析笔记

api/apps/__init__.py

导入依赖

导入了多个 Python 库和模块,包括日志记录、系统操作、模块导入、路径处理、Flask 框架、请求处理、CORS(跨源资源共享)支持等。还导入了项目特定的模块,如数据库模型、服务和工具函数。

import logging
import os
import sys
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
from flask import Blueprint, Flask
from werkzeug.wrappers.request import Request
from flask_cors import CORS

from api.db import StatusEnum
from api.db.db_models import close_connection
from api.db.services import UserService
from api.utils import CustomJSONEncoder

from flask_session import Session
from flask_login import LoginManager
from api.settings import SECRET_KEY, stat_logger
from api.settings import API_VERSION, access_logger
from api.utils.api_utils import server_error_response
from itsdangerous.url_safe import URLSafeTimedSerializer as Serializer

__all__ 声明

指定此模块公开的属性,这里只有 app

__all__ = ['app']

日志配置

创建一个名为 'flask.app' 的日志记录器,并将 access_logger 的处理程序添加到其中。

logger = logging.getLogger('flask.app')
for h in access_logger.handlers:
    logger.addHandler(h)

修改 Request 对象的 json 属性

将 Flask 的 Request 对象的 json 属性修改为一个属性,该属性会强制且静默地获取 JSON 数据。

Request.json = property(lambda self: self.get_json(force=True, silent=True))

Flask 应用初始化

创建一个 Flask 应用实例 app,并配置 CORS 支持、URL 映射的严格斜杠处理、自定义的 JSON 编码器和异常处理函数。

app = Flask(__name__)
CORS(app, supports_credentials=True,max_age=2592000)
app.url_map.strict_slashes = False
app.json_encoder = CustomJSONEncoder
app.errorhandler(Exception)(server_error_response)

应用配置

设置 Flask 会话的配置,如是否永久保存会话和会话类型。还从环境变量中获取最大内容长度,或默认为 128MB。

## convince for dev and debug
#app.config["LOGIN_DISABLED"] = True
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config['MAX_CONTENT_LENGTH'] = int(os.environ.get("MAX_CONTENT_LENGTH", 128 * 1024 * 1024))

初始化 Flask-Session 和 Flask-Login

初始化 Flask-Session 和 Flask-Login 的 LoginManager

Session(app)
login_manager = LoginManager()
login_manager.init_app(app)

动态路由注册

定义了两个函数 search_pages_path 和 register_page,用于搜索特定目录中的 *_app.py 文件,并动态加载这些文件作为 Flask 蓝图(Blueprint)注册到应用中。

def search_pages_path(pages_dir):
    return [path for path in pages_dir.glob('*_app.py') if not path.name.startswith('.')]


def register_page(page_path):
    page_name = page_path.stem.rstrip('_app')
    module_name = '.'.join(page_path.parts[page_path.parts.index('api'):-1] + (page_name, ))

    spec = spec_from_file_location(module_name, page_path)
    page = module_from_spec(spec)
    page.app = app
    page.manager = Blueprint(page_name, module_name)
    sys.modules[module_name] = page
    spec.loader.exec_module(page)

    page_name = getattr(page, 'page_name', page_name)
    url_prefix = f'/{API_VERSION}/{page_name}'

    app.register_blueprint(page.manager, url_prefix=url_prefix)
    return url_prefix

搜索并注册蓝图

指定搜索蓝图的目录,并使用前面定义的函数搜索并注册这些蓝图。

pages_dir = [
    Path(__file__).parent,
    Path(__file__).parent.parent / 'api' / 'apps',
]

client_urls_prefix = [
    register_page(path)
    for dir in pages_dir
    for path in search_pages_path(dir)
]

用户加载函数

为 LoginManager 定义一个 request_loader,该函数从请求的头部获取 JWT 令牌,并尝试使用它来加载用户。如果令牌有效且用户状态有效,则返回用户对象;否则返回 None

@login_manager.request_loader
def load_user(web_request):
    jwt = Serializer(secret_key=SECRET_KEY)
    authorization = web_request.headers.get("Authorization")
    if authorization:
        try:
            access_token = str(jwt.loads(authorization))
            user = UserService.query(access_token=access_token, status=StatusEnum.VALID.value)
            if user:
                return user[0]
            else:
                return None
        except Exception as e:
            stat_logger.exception(e)
            return None
    else:
        return None

请求结束时的数据库连接关闭

使用 Flask 的 teardown_request 装饰器定义一个函数,该函数在每个请求结束时关闭数据库连接。

@app.teardown_request
def _db_close(exc):
    close_connection()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汝欲往

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值