网站首页 > 技术文章 正文
用一系列文章介绍如何用python写一个发票管理小工具。
本文介绍如何用Uvicorn+FastAPI搭建后台接口,如何使用loguru打印日志,以及自动打开浏览器显示前端页面。
基本思路
大家一般运行Uvicorn都是uvicorn.run()直接运行,这样uvicorn启动后会阻塞程序,后续无法执行代码。
所以这里我们使用Python多进程,一个主进程用于打开浏览器以及后续其他功能,一个独立的子进程运行Uvicorn。
配置文件
创建一个配置文件config.yml,编写config.py用于读取配置文件。使用ruamel.yaml模块读取yaml文件。
#config.py
from ruamel.yaml import YAML
class AppConfig():
def __init__(self):
with open("config/config.yml","r",encoding="utf-8") as configFile:
yaml = YAML()
conf = yaml.load(configFile)
self.config = conf
self.loguru = self.config['loguru']
self.uvicorn = self.config['uvicorn']
appConfig = AppConfig()
# config.yml
# 日志配置
loguru:
format: '{time:YYYY-MM-DDTHH:mm:ss.SSSZ} {level} tid[{extra[tid]}] {message}'
level: DEBUG
file: logs/application.log
rotation: 00:00
retention: 30 days
# uvicorn设置
uvicorn:
host: 127.0.0.1
port: 8088
# 等待web服务启动时间,服务启动后自动打开浏览器
waitWebServerTime: 10
独立进程运行Uvicorn
使用multiprocessing.Process创建子进程,注意设置daemon=True,这样主进程关闭时会自动关掉子进程。
import uvicorn
from multiprocessing import Process
from config import appConfig
def runUvicorn():
uvicorn.run("webapi:app", host=appConfig.uvicorn["host"], port=appConfig.uvicorn["port"], reload=False, log_config='config/uvicornLog.json', access_log=True, workers=1)
# 启动web服务
webapiProcess = Process(target=runUvicorn, name="webapi_process", daemon=True)
webapiProcess.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
logger.info("user interrupt, close application")
sys.exit(0)
日志增加TID
为了方便日志追踪,一般我们都会在日志中打印一个transaction_id,用户一个请求过程中的所有日志都有这样一个唯一的transaction_id。
我们使用loguru模块来打印日志,loguru配置和使用非常简单,而且我们的程序使用了多进程,loguru是支持多进程的。
第一节的配置文件中已经有loguru需要的配置项了,下面介绍如何使用loguru,以及fastapi如何生成transaction_id,并且将tid添加到日志中。
创建log.py
from loguru import logger
import sys
from config import appConfig
logger.remove()
logger.configure(extra={"tid":""})
logger.add(sys.stderr, enqueue=True, format=appConfig.loguru["format"], level=appConfig.loguru["level"])
logger.add(appConfig.loguru["file"], enqueue=True, format=appConfig.loguru["format"], level=appConfig.loguru["level"], rotation=appConfig.loguru["rotation"], retention=appConfig.loguru["retention"])
需要关注的是logger.configure(extra={"tid":""})这一行,将tid添加到日志record的extra中,extra是loguru提供给用户添加自定义日志字段的属性。虽然也有办法直接修改record,但是建议添加到extra中。
在webapi.py中添加middleware,在收到请求时生成tid。然后通过loguru的pach将tid添加到日志record中。
#webapi.py
from random import randint
from typing import Callable, Optional
from fastapi import FastAPI,Request
from loguru import logger
from datetime import datetime
from contextvars import ContextVar
# 用于日志记录当前请求ID
transaction_id: ContextVar[Optional[str]] = ContextVar('transaction_id', default='')
def transaction_id_filter(record):
record['extra']['tid'] = transaction_id.get()
return record
# 此处向日志中设置tid
logger.configure(patcher=transaction_id_filter)
app = FastAPI(title='My Invoice Folder', docs_url=None, redoc_url=None)
# 生成请求ID
@app.middleware("http")
async def create_transaction_id(request: Request, call_next: Callable):
# tid格式为时间戳+4位随机数
transaction_id.set(f"{datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]}{randint(1000, 9999)}")
response = await call_next(request)
return response
将fastapi首页设置为发票夹页面
我们之前已经写了一个发票夹html页面,这里直接将fastapi首页跳转到这个页面就可以了。
将页面资源都放到项目ui文件夹中,加载ui文件夹。
app.mount("/ui", StaticFiles(directory="ui"), name="ui")
设置首页跳转
# 首页跳转到我的发票夹页面
@app.get("/", include_in_schema=False)
def read_root():
logger.info("access index page")
return RedirectResponse("/ui/index.html")
自动打开浏览器显示发票夹页面
首先我们在启动Uvicorn进程后,使用request请求首页,如果请求成功,则打开系统默认浏览器并打开发票夹首页。代码如下:
# 启动系统默认浏览器打开界面
waitWebServerTime = appConfig.config["waitWebServerTime"]
openBrowserSuccess = False
while waitWebServerTime > 0:
time.sleep(1)
try:
# 判断web服务是否已启动
indexUrl = f'http://{appConfig.uvicorn["host"]}:{appConfig.uvicorn["port"]}/'
response = requests.get(indexUrl, timeout=1)
if response.status_code == 200:
# 打开主页
openBrowserSuccess = openBrowser(indexUrl)
break
except Exception as e:
pass
waitWebServerTime -= 1
总结
现在我们可以直接运行main.py,就可以运行后端api,并且自动打开浏览器看到页面了~后续逻辑抽空继续写。
代码比较多,已经上传到github(https://github.com/xy12358/my-invoice-folder.git)和gitee(https://gitee.com/xinying/my-invoice-folder)。
猜你喜欢
- 2024-09-26 由浅入深写代理(4)-socks5-代理(sock 代理)
- 2024-09-26 限定源端口访问目标(指定源端口)
- 2024-09-26 这些键盘按键知识,你知道吗?(键盘按键功能详解图全解)
- 2024-09-26 python中的异常处理try except(Python中的异常处理语句包括哪些?)
- 2024-09-26 创建win后台任务定时用Python代码发邮件
- 2024-09-26 单片机按键设计的改善(单片机按键程序设计)
- 2024-09-26 在Python中使用Asyncio系统(3-6)?优雅地开启和关闭协程
- 1515℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 576℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 514℃MySQL service启动脚本浅析(r12笔记第59天)
- 487℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 486℃启用MySQL查询缓存(mysql8.0查询缓存)
- 470℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 450℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 448℃MySQL server PID file could not be found!失败
- 最近发表
-
- 宝塔面板Nginx如何提高网站访问速度?
- 接口调试工具ApiPost中form-data/x-www-form-urlencoded/raw区别
- 高并发场景下,Nginx性能如何提升10倍?
- 高并发场景下,Nginx如何抗住千万级流量?
- 浏览器中在线预览pdf文件,pdf.mjs插件实现web预览pdf
- 为什么你的网站加载慢?90%的人忽略了这2个设置。
- 别再无脑复制Nginx配置了!掌握这10个"性能核弹"级参数
- 你的Nginx配置,可能就是你网站最慢的一环,注意这几个优化参数
- 深入浅出HTTP压缩技术(http2压缩)
- C程序设计之:1-1/2+1/3-... + 1/n 的和
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (83)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)