自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(322)
  • 收藏
  • 关注

原创 Python后端复杂业务04:用户只点了一次,服务器可能收到两次——幂等键与原响应收据

客户提交订单,服务器已经预留库存并提交数据库,但响应在回到客户端之前断开。客户端只看到了超时,不知道订单究竟有没有成立。如果重试时直接创建新订单,同一笔购买意图会占两份库存;如果完全不重试,客户又可能不知道自己已经有一张待付款订单。幂等键解决的是这种结果不确定性:客户端为一次逻辑动作生成稳定标识,重试时仍使用它,服务器保存该动作的请求指纹与原响应。它不是一个“防止重复点击”的前端技巧,也不是把任何相似订单都去重。两次真实购买即使内容相同,也应该使用不同键并分别成立。

2026-11-10 09:19:08 135

原创 Python后端复杂业务03:最后一件商品究竟卖给谁——库存预留、写事务与取消释放

E03 使用两个线程,每个线程建立自己的 TestClient,但都指向同一个应用和同一个临时数据库。它们各自生成不同的 Idempotency-Key,在 Barrier 处等待,然后同时提交购买 LAST 一件的请求。不同的键很关键,否则两次请求可能只是同一逻辑动作的幂等重试,无法验证两个独立订单之间的库存竞争。两个响应的顺序没有保证,所以答案排序后断言[201, 409],而不是认定线程甲必须成功。

2026-11-10 09:18:57 103

原创 Python后端复杂业务02:价格会变,已经成立的订单不能跟着变——整数金额与购买快照

客户昨天以二十五元买了一只鼠标,今天商品调价到三十元。客服查询订单时如果临时连接商品表计算金额,会告诉客户“你买的是三十元”;退款程序如果也查询当前价格,又可能多退五元。支付当时没有错,商品调价也没有错,真正的问题是系统没有区分当前报价与已经成立的购买约定。本课把钱与数量的边界落实到输入模型、订单行和后续计算。整数分解决金额表示,价格快照解决历史事实,严格数量解决意外类型转换,重复 SKU 校验解决一个订单里对同一商品的含义冲突。这些规则共同保证客户、仓库与资金流水讨论的是同一份购买约定。

2026-11-10 09:18:46 215

原创 Python后端复杂业务01:订单不是一个 status——钱、货与事件为什么要分开记

所有业务接口都要求X-API-Key。它是一套内部教学调用凭据,用来阻止完全匿名的请求,不是客户登录系统,也不是每个消费者的资源授权模型。是内部调用者传来的业务引用,例如 alice;不能因为字段看起来像用户名,就声称系统已经验证了 Alice 的真实身份。密钥由实验环境随机生成,配套sandbox()返回已经构造好的 headers。答案不会打印密钥,也不会把它硬编码进正文。健康检查不要求这个头,业务接口则在缺失或错误时返回 401。生产系统若要开放给终端用户,需要另外设计用户身份、组织边界和资源权限。

2026-11-09 09:07:50 413

原创 Python后端权限系统14:完成采购平台验收,把认证、授权、审计与OIDC串成闭环

毕业验收不应该只是把前十三篇命令再执行一遍。我们需要站在真实业务的角度,证明一个合法申请能够完成整个流程,同时错误身份、错误租户、错误状态和过期版本都无法偷偷修改它。最终产物是可以安装和运行的ProcureSafe、可独立执行的课后答案、对应的完整源码、教学图片与验收报告。每个结果都要说明执行环境,尤其不能把内存测试描述成公网身份认证。这次业务旅程从Alice申请设备开始,经过Bob审批、Buyer下单和Finance标记付款,最后由Admin查看审计。

2026-11-09 09:07:37 411

原创 Python后端权限系统13:登录锁定、即时禁用与部署边界,把安全规则落到运行环境

系统在正确请求下运行顺畅,还不足以应对真实使用。攻击者可以不断猜密码,离职员工可能握着尚未过期的token,开发时临时关闭的Secure cookie也可能被带到生产。本篇把这些问题接回已经建立的会话与成员体系,不用一张含糊的“上线前注意安全”清单代替可观察的行为。我们先定义登录失败后发生什么,再区分账号禁用、角色撤销、会话登出各自影响哪个范围。所有实验仍使用临时SQLite、随机演示口令和可注入时钟。我们不会要求你真的等一分钟,也不会把机器系统时间往后改。

2026-11-09 09:07:22 266

原创 Python后端权限系统12:把权限矩阵变成负例测试,验证并发刷新唯一消费

权限代码很容易在第一次演示时看起来正确:Alice能提交,Bob能审批,采购员能下单,财务能标记付款。但业务通常在新增角色、兼任部门、批量处理和重试时出现漏洞。与其不停增加“看起来更保险”的if,不如先把规则拆成能够重复验证的行为。本篇把主体、租户、资源关系、动作、状态与版本放在同一张矩阵中,再用并发刷新实验说明:顺序请求都正确,不代表竞争发生时仍然正确。测试不是证明世界上不存在攻击,而是给已承诺的边界提供持续证据。我们会清楚区分业务拒绝、身份失效和状态冲突,也会把拒绝后数据不变纳入断言。

2026-11-08 14:26:48 404

原创 Python后端权限系统11:从JWKS验签到nonce,让身份声明真正可被信任

上一课已经拿到一个形如三段Base64URL字符串的ID Token。现在最危险的一行代码不是密码比较,而是“解码后直接读取sub”。任何人都可以编码一段JSON;即使JWT签名有效,它也可能来自错误供应商、发给另一个应用、已经过期,或属于另一场登录流程。本篇把这些条件逐个落到真实实现和负例实验中,解释为什么每次只能改变一个条件,才能知道验证器究竟守住了哪道边界。我们继续使用固定可信issuer与RS256,不实现任意供应商自动发现入口。

2026-11-08 14:26:34 227

原创 Python后端权限系统10:走通授权码与PKCE,把外部身份接入本地会话

公司已经有统一登录入口,采购平台不希望再要求每个人记住一份密码。接入时最容易犯的错误,是看到第三方回传一个token,就把里面的email当成当前用户。这个跳跃漏掉了协议用途、发放对象、请求关联和本地账号绑定。本篇先建立正确的数据流:浏览器取得短期授权码,ProcureSafe用自己保留的PKCE验证材料换取ID Token,验证身份声明后,再签发本系统自己的opaque会话。教学项目附带一个本地协议对端。它使用真实RSA签名、公开JWKS和授权码兑换接口,但授权端固定选择demo-alice。

2026-11-08 14:26:23 420

原创 Python后端权限系统09:让审计与业务一起提交,留下够用而不过量的证据

好的事件结构应服务于具体调查。这里需要回答:哪个已认证用户,在什么时间,对哪个资源,发起了什么动作,结果成功还是拒绝,对应哪次请求?因此API允许返回的字段是time、actor、action、resource_id、result和request_id。tenant_id用于数据库内部分区,但查询已经受到目标租户和租户管理员身份限制,输出不需要把整张内部审计表原样暴露。

2026-11-06 09:16:10 369

原创 Python后端权限系统08:从查询条件守住租户边界,拆解跨租户IDOR

采购平台已经能识别员工、部门经理和采购员,但现在要服务两家公司。Alice属于Acme,Mallory属于Beta。两个人都有合法账号,都能成功登录,也都能创建申请。如果Alice把详情地址最后一段换成Mallory的申请编号,系统应该怎样回答?这不是密码问题,也不是令牌是否有效的问题,而是一个已认证用户试图越过资源边界。认证做得再好,也不会自动给每条数据库查询补上租户条件。本篇沿用完整项目ProcureSafe,不创建第二套演示模型。运行目录为本专题的project,先按README安装依赖。

2026-11-06 09:15:57 425

原创 从 SSH 超时到系统恢复:鲲鹏 ARM 服务器 XFS 根分区修复实战

一台鲲鹏ARM服务器因XFS根分区日志恢复失败导致无法SSH连接。通过iBMC KVM接入,确认故障源于非正常关机后日志回放失败。为避免数据风险,未直接修复原卷,而是利用125GiB内存构建RAM COW快照,在可写副本上试修。经验证修复成功后,对原卷执行xfs_repair -L并恢复系统。最终服务器正常启动,SSH与Ping恢复正常,7个丢失inode被找回。关键经验:管理口可用≠系统已启动;mount -o ro仍可能触发日志回放;xfs_repair -L有数据丢失风险,需谨慎使用。

2026-11-06 09:15:40 659

原创 Python后端权限系统07:经理也不能批准自己的采购——资源策略、职责分离与状态推进

Bob 是 acme 工程部门经理。他提交了一张高价设备采购,随后使用同一个账号点击批准。只检查的接口会立即放行,从形式上满足“只有经理能审批”,却违背了组织最想要的约束:申请者不能同时成为自己的审核者。角色检查正确,并不保证业务授权正确。本课把授权从角色列表推进到资源策略。我们会同时看当前用户、成员部门、资源所有者、动作与状态,并区分两种不同问题:这张申请对当前用户是否可见,以及当前用户能否在此刻执行这个动作。最后把判断放进事务,防止两个并发请求把同一个旧版本推进两次。

2026-11-05 09:15:38 392

原创 Python后端权限系统06:角色属于哪家公司——成员关系、管理范围与立即撤权

Bob 上午还是工程部门经理,下午已经调岗。管理员在人员管理页面撤下了他的 manager 角色,但 Bob 浏览器里的 access token 还剩八分钟才到期。他试着批准 Alice 的采购申请。如果接口依旧允许,权限页面展示的“已经撤权”就与真实业务能力发生了冲突。本课围绕这一件事设计组织模型:用户身份可以跨请求稳定存在,组织成员关系却必须反映当前事实。角色不是用户名的一项永久属性,也不是客户端传来的自我描述;它属于某个用户在某个租户中的成员关系。

2026-11-05 09:15:27 364

原创 Python后端权限系统05:Cookie 会自己跟着请求走——Origin、CSRF 与浏览器凭据边界

Alice 保持采购系统的登录状态,同时打开了一篇外部网页。网页里藏着一个表单,提交目标是采购系统的创建申请接口。即使外部网页读不到响应,浏览器仍可能按照自己的 Cookie 规则把 Alice 的凭据附在请求上。服务器如果只看“有合法 Cookie”,就可能以 Alice 的身份执行这次并非她想要的写入。这就是本课要分析的跨站请求伪造问题。它不是攻击者破解了随机令牌,也不要求攻击者知道密码;问题出在浏览器替用户自动携带了认证材料,而服务器没有区分用户真正发起的应用操作与外部站点诱导的请求。

2026-11-05 09:15:17 272

原创 Python后端权限系统04:刷新不是续一张票——单次轮换、重放检测与事务竞争

Alice 的浏览器和一个窃取了凭据的脚本,都持有同一个 refresh token。浏览器先刷新得到新 access token,窃取者随后拿旧 refresh 再刷新。如果服务端只检查“这段字符串是否存在、是否过期”,两边都可能得到新凭据,甚至持续互相接力。这时缩短 access 的生存期没有真正结束被盗会话,因为续签入口一直保持开放。本课给 refresh 加上历史:它属于哪一次登录,是否已经被消费,谁是这次轮换的新凭据,以及发现重复使用后如何撤销整条会话链。

2026-11-04 18:00:00 676

原创 Python后端权限系统03:登录之后还要继续核验——不透明令牌、过期与退出登录

服务端不需要重新取出原始 access token。客户端每次带来它,服务端计算相同的摘要后查找即可。ProcureSafe 使用 SHA-256 保存令牌摘要,原始令牌只在签发响应中交付。这样,单独拿到会话表的读取者不能直接把摘要当作 Bearer 值使用。上一课要求对密码使用慢散列,这里却使用快速 SHA-256,看起来似乎矛盾。区别在输入的熵:人类口令通常来自可猜测分布,需要提高每次猜测成本;本项目令牌由密码学随机源生成,具有足够随机性,攻击者无法合理枚举候选空间。

2026-11-04 09:11:51 656

原创 Python后端权限系统02:数据库泄露之后,密码还能守住什么——scrypt 与统一登录失败

假设采购系统有一天泄露了用户表。攻击者得到的若是明文口令,事件几乎立即扩展到邮件、办公平台及其他被重复使用口令的系统。若数据库里只有一次普通 SHA-256 的结果,也不能因此放心:常见口令可以被快速批量计算,攻击者不必再经过我们的登录接口和失败次数限制。本课讨论的是这个具体场景:让数据库保存可以验证口令、但不直接提供口令的信息,并尽量提高离线猜测的成本。它与限制在线登录次数是两条独立防线。密码散列做得再慢,仍然需要保护登录入口;登录限流做得再严,也保护不了已经被复制到攻击者机器上的散列数据库。

2026-11-04 09:11:36 384

原创 Python后端权限系统01:先画边界,再写登录——采购申请中的身份、动作与资源

周五下午,工程部门的 Alice 提交了一笔设备采购。负责销售部门的 Carol 复制了审批链接,页面里却出现了“同意采购”按钮;另一家公司的 Mallory 把链接里的租户名称改成自己的公司,意外看到了相同编号的申请。开发者第一反应往往是“隐藏按钮”“把编号改成长一点”。这两种办法都没有回答真正的问题:服务端凭什么相信当前请求可以读取或改变这张申请?本专题用一个独立项目 ProcureSafe 回答这个问题。它是一套可运行的教学采购系统,使用 Python 3.11、FastAPI 和 SQLite。

2026-11-03 18:00:00 110

原创 Python后端部署排障18:从空环境到清理无残留,完成一次能重做的交付

毕业自测不是再加一个新服务,而是审核最终清理证据。题目要求:读取本次cleanup报告,验证status为PASS,所有remaining_owned列表为空,输出本次登记资源数量;错误报告必须以非零状态退出。以下标准库脚本可直接保存为,完整文件也随项目提供。main()这份审计不会重新操作Docker,也不会把一份静态JSON等同于当前机器状态。它回答“报告是否满足约定”,E17的独立标签查询回答“删除当时是否仍有本次容器、网络或卷”。二者职责清楚。

2026-11-03 09:10:26 548

原创 Python后端部署排障17:把“我会部署”写成别人也能执行的操作手册

项目可以启动,作者也能在脑中补齐十几个隐含步骤,但另一位同学照README操作时仍然失败:忘了执行迁移、不知道当前流量在哪个槽位、备份覆盖了旧文件、清理时误删其他实验卷。缺少的不是另一条Docker命令,而是操作前提、检查点、失败时的返回路径和资源归属。这篇把QuoteOps整理成可交接的手册。手册面向当前这个个人实验:已有授权的Linux主机、仅本机监听的高端口、独立Compose项目、受控SQLite卷。它不把课程扩大成公网认证系统,也不引入Kubernetes。

2026-11-03 09:10:14 211

原创 Python后端部署排障16:先别重启,给上游故障留下一条能复盘的证据链

入口突然返回502。你可以立刻重启所有容器,几分钟后看到页面恢复;也可以先花很短时间记录本次请求、活动版本、上游状态和配置,再选择只恢复故障组件。两种做法都可能让页面重新打开,只有后者更容易回答“为什么故障”和“下次怎样提前发现”。故障演练的价值不在于制造尽可能多的红色输出,而在于控制变量。我们先创建一张有明确金额的报价,只停止当前承接流量的应用容器;Nginx继续运行,数据卷继续保留。故障期间入口必须出现502或504,并记录实际状态和响应正文;恢复后同一个报价id应返回完全相同的业务内容。

2026-11-02 18:00:00 473

原创 Python后端部署排障15:容器退出137,就一定是内存不够吗

应用突然退出,终端显示137。有人立即把内存限制扩大一倍,重新启动后服务似乎恢复了。真正的问题可能是人工执行了强制终止,也可能是平台在宽限期结束后发送SIGKILL;这些场景同样可以留下137。资源故障最危险的地方,是现象容易记住,原因却需要额外证据。这篇不靠耗尽宿主机制造“真实感”。我们把写满实验放进仅8MiB的tmpfs,把进程、内存和CPU也限制在专属小容器里。发生ENOSPC后,脚本只删除自己创建的文件,再验证新写入成功。

2026-11-02 08:58:34 320

原创 Python后端部署排障14:用户说刚才失败了,你能找到那一条请求吗

同一时刻,Nginx写了一行502,应用写了几十行200,Docker健康检查仍是healthy。三条信息都可能真实,却不一定属于同一条请求。若把它们直接拼成故事,就会得出“应用明明成功,代理一定误报”的结论。排障首先需要一个可靠的关联键,然后才讨论状态码、耗时和错误原因。QuoteOps沿用报价服务的。入口接收合规的标识或生成新值,再转发给应用;应用将同一标识写进响应与结构化日志。日志只选择白名单字段,不记录查询字符串、Authorization或请求正文。

2026-11-02 08:58:24 375

原创 Python后端部署排障13:切回旧镜像,为什么数据没有跟着回去

发布后的第一笔报价金额不对,值班同学切回了旧镜像,页面重新显示v1。大家松了一口气,随后发现刚刚产生的错误数据还在。有人建议把数据库文件也换回昨天的备份,另一位同学则指出:这样会同时抹去今天所有正确的报价。这次分歧不在命令,而在大家说“回滚”时指向了不同的对象。本篇把应用版本、数据库结构、业务记录和备份快照分开讨论。QuoteOps的v1与v2使用相同业务代码、相同schema和同一个受控SQLite卷,只有的release不同。

2026-10-30 09:17:05 353

原创 Python后端部署排障12:怎样发布v2,才能证明失败时流量仍在v1

发布成功”不能只定义为镜像构建成功,也不能只看重载命令退出0。真正需要证明的是:候选版本具备接流量的条件,入口已经指向它,原有业务数据仍能正确读取,而失败路径不会把正在工作的版本带走。本课把这些条件组成一个小型蓝绿发布流程,并让拒绝坏候选成为必测步骤。

2026-10-30 09:16:54 433

原创 Python后端部署排障11:health返回200,为什么用户请求还是503

把进程活着当作服务可用,是部署中最有迷惑性的判断之一。Python能启动、Uvicorn在监听、TLS握手成功,数据库却可能没有迁移,真正的业务请求仍然失败。健康检查不是一个绿色灯泡,而是一组针对不同决策的合同。本课把启动、就绪、存活和停止放到同一条时间线上,避免用重启掩盖根本原因。

2026-10-30 09:16:43 266

原创 Python后端部署排障10:端口能连,为什么HTTPS仍然拒绝连接

一次curl失败可能发生在HTTP之前。TCP握手成功只能说明网络可达,TLS还要协商加密参数、验证对方身份并建立可信连接。很多初学者遇到证书错误就加-k,得到200后认为问题解决,实际上绕过了本来要验证的身份条件。本课建立独立实验CA,分别证明正确连接、主机名错误和缺少信任根三种情况。

2026-10-29 09:21:09 449

原创 Python后端部署排障09:应用明明活着,Nginx为什么返回502或504

如果直接访问应用容器能得到200,经过统一入口却失败,继续检查业务公式通常没有意义。请求在到达业务代码前还要经过监听端口、服务名解析、TCP连接和代理规则。本课让Nginx成为可以观察、可以验证、可以恢复的一环,通过受控故障回答502与504究竟差在哪一层。

2026-10-29 09:20:58 438

原创 Python后端部署排障08:容器重建后,报价为什么不该消失

服务在一个容器里跑通后,最常见的错误是把它想成一台缩小的服务器:代码、数据、日志和配置全部放进去,删除后再从头安装。容器部署真正要建立的是可重复创建进程的能力,数据则有独立的保存策略。本课把blue、green、edge以及数据库卷连接起来,通过一次真实重建检查这个边界。

2026-10-29 09:20:48 298

原创 Python后端部署排障07:为什么代码没变,换台机器就启动失败

上一课已经让报价经过创建、读取、确认和版本冲突检查。现在把同一份代码交给另一台机器,新的问题却出现了:解释器版本不同,缺一个依赖,工作目录改变,数据库路径变成另一个位置。把这些故障都归为“环境问题”没有诊断价值。本课把环境拆成可以检查的镜像、进程入口、运行身份和数据位置,为下一课的多容器部署建立合同。

2026-10-28 09:37:32 568

原创 Python后端部署排障06:curl 没报错,为什么业务请求还是失败了

网络层已经连通,curl 也输出了一段 JSON,于是你在群里说“恢复了”。几分钟后用户仍无法确认报价:原来 JSON 是一个版本冲突错误,HTTP 状态为 409,curl 却默认以零退出。这个小坑揭示了本课的核心:命令执行成功、HTTP 收到响应、业务操作成功,是三件需要分别验证的事。我们从可观察的 HTTP 请求开始,不急着安装代理和证书。先在本机回环地址运行本专题自带的 QuoteOps,用 curl 检查方法、请求头、body、响应头和状态,再完成一次创建、读取、确认、旧版本拒绝的业务闭环。

2026-10-28 09:37:20 315

原创 Python后端部署排障05:域名已经解析出来,为什么连接仍被拒绝

浏览器显示“连接失败”,有人开始清 DNS 缓存,有人重启应用,也有人怀疑防火墙。问题在于这句话把多层过程压成了一个结果。一次 HTTP 访问至少需要选定目标地址、建立传输连接,再按协议交换请求与响应;HTTPS 还要完成 TLS。上一层成功,只能把下一层变成可能,不能替下一层作保证。本课用标准库把解析与连接拆开。我们不借助不稳定的公网域名,不扫描别人的端口,而是在本机回环地址上占用一个自动分配的端口。先只绑定、不监听,让连接失败;再开始监听,让同一地址恢复成功。

2026-10-28 09:37:05 222

原创 Python后端部署排障04:磁盘还有空间,为何文件就是打不开

打不开文件”描述的是结果,并没有指出资源瓶颈。路径不存在、权限不足、进程文件描述符耗尽、磁盘块耗尽、inode 耗尽,都可能出现在业务访问文件的附近,但修复方法完全不同。把这些错误一律归为磁盘满,再随手删除日志,既可能无效,也可能丢掉最有价值的现场。本课从一个有趣的差别出发:关闭文件会释放文件描述符,但不一定删除文件;删除文件名会减少目录项,但不一定立即回收文件数据。内核管理的是多种不同对象。只要分清“文件名、打开的引用、存储空间”,你就能解释很多看起来互相矛盾的输出。

2026-10-27 09:15:12 462

原创 Python后端部署排障03:关掉终端以后,谁还在照看 Python 进程

你在 SSH 终端启动服务,看见启动日志,接口也能访问。第二天登录,服务消失了。另一种情况恰好相反:终端已经关闭,旧进程仍占着端口,新版本怎么启动都失败。这两种现象都说明,我们需要把“执行了一条命令”升级为“管理一个有身份、有状态、有结束流程的进程”。本课先做一个很小的 worker。它只维护心跳和 PID 文件,收到停止信号时写下清理记录。因为没有数据库和网络请求干扰,我们可以专心观察谁启动了它、谁通知它退出、它有没有完成finally。

2026-10-27 09:14:57 317

原创 Python后端部署排障02:文件明明存在,为什么 Python 还是没有权限

有一种部署故障特别容易被“修好”:Python 报,执行一次,程序果然能写了。它像把办公楼所有门都拆掉,确实不再有人被门拦住,但你已经失去了原本想保护的边界。这一课要做到同样能恢复运行,而且知道到底是哪一扇门少了哪一把钥匙。权限问题不能只看最后那个文件。程序打开,必须沿路径经过多个目录,再对目标文件执行相应操作;数据库还可能需要在同目录创建日志文件。文件本身可写,父目录不可遍历,照样失败。我们先回收上一课的机器证据,再用普通用户在一次性目录中构造可控失败。

2026-10-27 09:14:45 471

原创 Python后端部署排障01:连上服务器以后,先证明自己站在哪里

程序在电脑上能运行,搬到服务器却“没反应”,第一反应常常是重装依赖。可是你可能在另一台机器,进入了另一个目录,或者正在看昨天启动的进程。排障的第一课不是背命令,而是把一句模糊的“服务器不行”改写成可以验证的事实:哪台主机、哪个用户、哪个目录、哪个进程、哪个端口,执行了什么,得到什么结果。这套课程叫 QuoteOps。业务是一个已经有明确合同的报价服务:创建报价、读取报价、用版本号确认或取消。我们把注意力从写接口转到让接口持续可用。本专题自带完整project/

2026-10-26 09:26:45 467

原创 Python后端工程化与测试16:让别人接手QuoteLedger,检验重构是否真正完成

你现在拥有的不是一组互不相干的pytest技巧,而是一个从单文件逐步演进的报价单服务。它经历过行为固定、包布局调整、领域规则提取、存储替换、迁移、版本冲突处理和质量门禁。最后要回答的问题是:没有参与开发的人,能否按照文档运行它;将来修改业务的人,能否知道哪些承诺受到测试保护。毕业验收因此同时看产物和解释。能启动不够,必须确认重启后数据存在、冲突不会覆盖、异常不会留下坏事务;工具全绿也不够,必须说清每种工具证明的范围。你不需要把项目包装成大型企业平台,但需要准确说明它已完成什么、尚未覆盖什么。

2026-10-26 09:25:18 408

原创 Python后端工程化与测试15:别把能启动的源码目录当成交付物

你把项目压缩给同事,同事解压后启动失败:开发时一直使用editable安装,代码依赖的模块恰好在工作目录里,wheel却没有包含它。另一种更隐蔽的问题是服务启动成功、也能创建报价单,重启后数据全没了,因为实际路径指向临时目录,或者仓库仍然使用内存字典。代码在开发机运行过,不能回答这些交付问题。这一课把QuoteLedger当成真正要交出去的安装包。我们构建wheel,在新建环境中安装,把工作目录切到源码以外,显式迁移一份临时SQLite文件,然后经历创建、停止进程、重启读取、确认和冲突。

2026-10-26 09:24:50 431

原创 Python后端工程化与测试14:你电脑上全绿,为什么合并后别人还是跑不起来

开发者提交前忘了运行mypy,或者只在自己电脑里装过一个没有写进依赖的包,代码都可能在合并后才出问题。团队不能靠“每个人记得点一遍”保证质量。持续集成的实际作用,是让每次变更在干净环境中执行约定的检查,并把结果绑定到那次变更,而不是额外发明一套只在服务器上才能理解的魔法命令。这一课把上一课的quality入口放进GitHub Actions。我们会逐段解释工作流文件、验证失败退出怎样向上传递,再讨论代码审查应关注什么。

2026-10-23 09:25:50 261

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除