
1. 从一个真实的小项目说起为什么接口设计和异常处理总在拖后腿做过几个小项目的人大概都有这种体会功能跑通了自己测也没问题但一交给别人用或者一上线各种奇怪的问题就冒出来了。请求参数少传了一个字段后端直接抛了个500第三方接口超时了整个页面卡死用户输入了一个空字符串数据库里多了一条脏数据。这些问题十有八九不是业务逻辑写错了而是接口设计和异常处理这两块没做到位。我最近在做一个内部用的小工具前后端加起来大概十几个接口规模不大但麻雀虽小五脏俱全。一开始我想着小项目嘛接口随便定一定异常直接try-catch包一下就行了。结果联调的时候前端同学拿着我的接口文档来问“这个字段是必填还是选填”“返回的code有哪些值”“超时了我该重试还是直接提示用户”我一时半会儿还真答不上来因为我自己写的时候也没想清楚。后来我换了个思路把接口设计和异常处理这两块交给AI来帮我梳理和补齐效率提升非常明显而且最终出来的方案比我拍脑袋想的要严谨得多。这篇文章就是把这个过程完整地拆开讲一遍。我会说清楚AI在哪些环节能帮上忙、怎么提问才能拿到可用的结果、生成的内容哪些能直接用哪些必须自己改以及我在这个过程中踩过的坑。适合正在做小项目、独立开发、或者带小团队做MVP的朋友参考。不管你是前端还是后端只要涉及到接口对接这里面的思路都能用得上。2. 接口设计这件事AI到底能帮到什么程度2.1 先搞清楚接口设计的核心难点在哪里很多人觉得接口设计就是定个URL、选个GET还是POST、把字段列出来就完事了。真做过项目的人知道难点根本不在这里。接口设计真正难的是边界情况的覆盖和一致性。边界情况包括必填字段缺失怎么办、字段类型不对怎么办、数值超出范围怎么办、分页参数传了负数怎么办、时间格式不统一怎么办。这些问题如果设计阶段没考虑到开发阶段就会变成一个个临时补丁最后代码里到处是if-else维护起来非常痛苦。一致性则是另一个隐形杀手。比如有的接口返回{code: 0, data: ...}有的返回{status: ok, result: ...}前端每对接一个接口就要重新适配一次。小项目里接口少还能忍接口一多就是灾难。AI在这两个点上恰好有优势。它见过大量的接口设计案例能快速帮你列出你可能没想到的边界情况也能帮你把返回格式统一起来。但前提是你要给它足够清晰的上下文不能只丢一句“帮我设计一个用户登录接口”就完事。2.2 我实际使用的提问框架我摸索出来一套比较有效的提问结构分四步走第一步交代项目背景和技术栈。比如“这是一个前后端分离的小项目后端用Python FastAPI前端用React数据库是PostgreSQL接口风格偏RESTful”。第二步说明业务场景和角色。比如“这个接口是给管理员用的用来批量导入用户数据单次最多500条”。第三步列出你已经想到的字段和规则。哪怕不完整也没关系AI会帮你补全。第四步明确要求输出格式。比如“请输出接口路径、请求方法、请求参数表、响应参数表、错误码列表、以及至少5个边界情况说明”。这套框架的好处是AI拿到之后不会泛泛而谈而是针对你的具体场景给出可落地的内容。我试过只给一句话的提问出来的东西看着挺全但仔细一看全是通用模板没法直接用。加上背景和约束之后质量完全不一样。2.3 AI生成的接口文档哪些能直接用哪些必须改先说能直接用的部分。参数表的字段名、类型、是否必填、示例值这些AI生成的质量通常不错尤其是常见业务场景它列得比我自己想的还全。错误码列表也是AI的强项它会按照HTTP状态码和业务错误码两层来组织覆盖得比较完整。边界情况说明往往能给我惊喜比如它会提醒我“批量导入时如果某一条数据格式错误是整批回滚还是跳过继续”这种问题我自己设计时真不一定能想到。必须自己改的部分也很明确。业务特有的校验规则AI不可能知道比如“手机号必须是特定号段”“导入的部门名称必须和现有部门匹配”这些只能自己补。性能相关的设计AI给的建议偏保守比如分页默认值它可能建议20但你的实际数据量可能需要100。权限和鉴权逻辑AI给的往往是通用方案具体到你的项目怎么设计角色和权限还是得自己拿主意。提示AI生成的接口文档一定要逐条过一遍尤其是涉及金额、权限、数据可见范围的部分不能直接复制粘贴就用。3. 异常处理从“到处try-catch”到“分层兜底”3.1 异常处理最容易犯的三个错误我在小项目里见过太多异常处理的反面教材总结下来主要是三个问题。第一个是捕获了但不处理。代码里写个try: ... except Exception: pass异常被吞掉了出了问题连日志都查不到。这种写法比不写try-catch还危险因为它掩盖了问题。第二个是异常信息直接暴露给用户。数据库报错的原样返回给前端用户看到一堆英文堆栈既看不懂又不安全。正确的做法是给用户看友好的提示把详细信息记到日志里。第三个是没有统一的异常出口。每个接口各自处理各自的异常有的返回{error: xxx}有的返回{message: xxx}前端处理起来非常麻烦。这三个问题的根源其实是一样的没有在架构层面把异常处理当成一个独立的事情来设计而是把它当成业务代码的附属品。AI在这个环节的价值就是帮你把异常处理从“附属品”提升为“独立层”。3.2 让AI帮你设计异常分层结构我的做法是让AI帮我设计一个分层的异常处理结构具体来说分三层第一层是参数校验层。在请求进入业务逻辑之前先把参数格式、必填项、类型、范围校验一遍。这一层的异常通常是400级别的返回给用户的信息要具体比如“字段email格式不正确”。第二层是业务逻辑层。这一层处理业务规则相关的异常比如“余额不足”“库存不够”“重复提交”。这一层的异常通常是422或者409级别的返回的信息要能让用户理解发生了什么。第三层是系统层。这一层处理数据库连接失败、第三方接口超时、内存溢出这类问题。这一层的异常通常是500级别的返回给用户的信息要模糊化比如“服务暂时不可用请稍后重试”但日志里要记录完整信息。我把这个分层思路告诉AI之后它帮我生成了每一层的异常类定义、统一的异常处理器、以及每一层对应的错误码规范。这部分代码我基本是直接用的只改了一些命名和日志配置。3.3 统一异常出口的具体实现统一异常出口的核心思路是不管哪里抛出的异常最终都汇聚到一个地方处理由这个地方决定返回给前端什么格式。在FastAPI里我让AI帮我生成了一个全局异常处理器大致结构是这样的from fastapi import Request from fastapi.responses import JSONResponse class AppException(Exception): def __init__(self, code: int, message: str, detail: str None): self.code code self.message message self.detail detail app.exception_handler(AppException) async def app_exception_handler(request: Request, exc: AppException): return JSONResponse( status_code200, content{ code: exc.code, message: exc.message, detail: exc.detail } ) app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): logger.error(fUnhandled exception: {exc}, exc_infoTrue) return JSONResponse( status_code200, content{ code: 50000, message: 服务暂时不可用请稍后重试, detail: None } )这段代码的关键点在于业务异常和系统异常走不同的处理器业务异常的detail可以暴露给前端系统异常的detail只记日志不返回。HTTP状态码统一返回200用业务code来区分成功和失败这样前端只需要判断code就行不用同时处理HTTP状态码和业务code两套逻辑。注意统一返回200这个做法在纯RESTful风格里是有争议的但在小项目里非常实用能大幅降低前端的处理复杂度。如果你的项目对RESTful规范要求严格可以保留HTTP状态码的语义但要在文档里写清楚。4. 完整实操用AI补齐一个批量导入接口的设计与异常处理4.1 场景描述与初始需求我拿项目中一个真实的接口来演示整个流程。这个接口的功能是批量导入用户数据管理员上传一个CSV文件后端解析后批量插入数据库。初始需求很简单接收文件、解析、插入、返回成功条数和失败条数。如果只按这个需求写代码大概几十行就能搞定。但实际联调的时候问题一大堆文件格式不对怎么办、CSV里有重复数据怎么办、插入到一半数据库挂了怎么办、文件太大内存扛不住怎么办。这些问题我在初始设计时都没考虑。4.2 第一轮提问让AI补全接口设计我的提问是这样的项目背景FastAPI PostgreSQL前后端分离接口返回格式统一为{code, message, data}。 业务场景管理员批量导入用户上传CSV文件字段包括name、email、phone、department。 已想到的规则email不能重复phone必须是11位数字department必须是现有部门之一。 请输出接口路径、请求方法、请求参数、响应参数、错误码列表、边界情况说明。AI返回的结果里接口路径建议用POST /api/v1/users/batch-import请求方法POST请求参数是multipart/form-data格式的文件字段。响应参数包括total、success_count、fail_count、fail_details。错误码列了大概十几个覆盖了文件格式错误、文件过大、字段缺失、格式错误、重复数据、部门不存在等情况。边界情况说明里AI提了几个我没想到的点CSV文件编码不是UTF-8怎么办、文件里有空行怎么办、字段值前后有空格怎么办、单次导入数量上限是多少、导入过程中部分成功部分失败怎么返回。这些问题后来在开发中确实都遇到了。4.3 第二轮提问让AI设计异常处理方案拿到接口设计之后我接着提问基于上面的接口请设计异常处理方案。要求区分参数校验异常、业务异常、系统异常给出每类异常的触发条件和返回信息说明部分成功部分失败时怎么处理。AI给的方案里参数校验异常用40001到40099的错误码业务异常用42201到42299系统异常用50001到50099。部分成功部分失败的处理方式是不整体回滚而是逐条插入记录每一条的失败原因最后汇总返回。这个方案我觉得合理因为批量导入场景下一条数据有问题就整批回滚用户体验很差。但AI还提了一个我没考虑到的点如果失败率超过某个阈值比如50%应该整体回滚并提示用户检查文件。这个逻辑我后来加上了确实有用避免用户导入了一个格式完全不对的文件结果数据库里插了一堆脏数据。4.4 关键代码实现与参数选择文件大小限制我设的是10MB这个数字是算出来的。假设每条用户记录平均200字节10MB大概能放5万条。但实际业务中单次导入超过5000条就应该拆分所以我在代码里加了单次最多5000条的限制超过就返回错误提示用户分批导入。CSV解析我用的是Python内置的csv模块没有引入pandas因为pandas对小项目来说太重了。解析的时候指定编码为utf-8-sig这个编码能自动处理BOM头避免第一列字段名前面多一个不可见字符。这个坑我踩过当时调试了半小时才发现是BOM的问题。逐条插入的时候我用了一个事务包裹所有插入操作但每插入一条就检查一次失败原因。如果失败率超过50%抛出一个业务异常触发回滚。如果失败率低于50%提交事务把失败详情返回给前端。import csv from io import StringIO MAX_ROWS 5000 FAIL_RATE_THRESHOLD 0.5 async def batch_import(file_content: bytes, db): try: text file_content.decode(utf-8-sig) except UnicodeDecodeError: raise AppException(40001, 文件编码不支持请使用UTF-8编码) reader csv.DictReader(StringIO(text)) rows list(reader) if len(rows) MAX_ROWS: raise AppException(40002, f单次最多导入{MAX_ROWS}条当前{len(rows)}条) success_count 0 fail_details [] for index, row in enumerate(rows, start2): try: validate_row(row) await insert_user(db, row) success_count 1 except AppException as e: fail_details.append({row: index, reason: e.message}) fail_count len(fail_details) if fail_count / len(rows) FAIL_RATE_THRESHOLD: raise AppException(42201, 失败率过高已回滚请检查文件内容) return { total: len(rows), success_count: success_count, fail_count: fail_count, fail_details: fail_details[:100] }这段代码里fail_details只返回前100条避免响应体过大。这个细节也是AI提醒我的当时我觉得返回全部失败详情没什么问题但AI指出如果5000条全失败响应体会有几百KB前端渲染也会卡。4.5 实操现场记录从联调到上线的调整联调阶段前端同学反馈了两个问题。第一个是错误码太多记不住希望有一个错误码文档。我让AI基于代码里的错误码生成了一份Markdown表格包含错误码、含义、触发条件、建议处理方式前端直接照着这个表格做提示就行。第二个问题是文件上传进度无法显示。这个不是异常处理的问题但和接口设计有关。后来我把接口改成了先上传文件返回一个task_id然后前端轮询另一个接口查询导入进度。这个改动让接口从1个变成了3个但用户体验好了很多。上线之后还遇到一个真实问题有用户上传了一个20MB的文件虽然前端做了大小限制但有人绕过前端直接调接口。后端的文件大小限制是在读取完整个文件之后才判断的这时候内存已经吃掉了20MB。后来改成了流式读取边读边判断大小超过限制直接中断。这个问题AI在边界情况里提过但我当时觉得前端已经限制了就没在意结果还是踩了坑。5. 常见问题与排查技巧实录5.1 AI生成内容的质量参差不齐怎么办这个问题很常见。同样的提问方式有时候AI给的结果很精准有时候就很泛。我的经验是提问里包含的具体约束越多结果质量越高。比如“请设计异常处理方案”和“请设计异常处理方案要求区分参数校验、业务、系统三层每层给出至少3个具体错误码和触发条件”后者出来的结果明显更可用。另外如果第一轮结果不满意不要重新开一个对话而是在同一个对话里追加要求。比如“上面的错误码太笼统了请针对批量导入场景细化特别是文件解析阶段的错误”。AI有上下文记忆追加要求比重新提问效果好。5.2 错误码设计有哪些坑错误码设计最大的坑是位数不统一。有的用1、2、3有的用10001、10002前端处理起来很别扭。我建议统一用5位数字前两位表示类别后三位表示具体错误。比如40001表示参数校验类第1个错误42201表示业务类第1个错误50001表示系统类第1个错误。第二个坑是错误码和HTTP状态码混用。有的接口返回HTTP 400有的返回HTTP 200但body里code是400前端要同时判断两套逻辑。小项目里建议统一返回HTTP 200用body里的code区分简单直接。第三个坑是错误信息写得太技术化。比如“IntegrityError: duplicate key value violates unique constraint”用户根本看不懂。应该改成“该邮箱已被注册”。技术细节记日志就行不用返回给用户。5.3 批量操作的部分失败怎么处理最合理这个问题没有标准答案取决于业务场景。我总结了一个决策表场景建议策略理由数据之间有依赖关系整体回滚部分成功会导致数据不一致数据之间独立逐条处理记录失败用户体验好不用反复重试失败率可能很高设阈值超过则回滚避免插入大量脏数据数据量很大异步处理返回task_id避免请求超时我这个批量导入的场景属于数据独立、失败率可能高所以用了逐条处理加阈值回滚的策略。实际跑下来效果不错用户能看到具体哪几条失败了、为什么失败修改之后重新导入就行。5.4 异常日志怎么记才有用日志不是记得越多越好关键是记对地方。我的做法是参数校验异常记WARNING级别包含请求参数和失败原因业务异常记WARNING级别包含业务标识和失败原因系统异常记ERROR级别包含完整堆栈。所有日志都带上request_id方便追踪一次请求的完整链路。还有一个技巧是不要在循环里打日志。批量导入5000条如果每条失败都打一条日志日志文件瞬间爆炸。我的做法是循环里只收集失败详情循环结束后统一打一条汇总日志包含失败条数和前10条失败原因。提示日志里不要记录用户的密码、token、身份证号等敏感信息这个在项目初期就要定好规范后期补很麻烦。5.5 接口文档和代码不同步怎么办这是小项目里特别常见的问题。代码改了文档没改前端照着旧文档对接联调时才发现对不上。我的解决办法是让AI帮我从代码里反向生成文档。具体做法是把接口相关的代码路由定义、请求模型、响应模型、异常定义贴给AI让它生成Markdown格式的接口文档。每次代码有变动重新生成一次就行比手动维护文档靠谱得多。当然更好的做法是用FastAPI自带的OpenAPI文档代码即文档自动同步。但有些细节比如错误码的含义、边界情况的说明OpenAPI表达不了还是需要一份补充文档。我的做法是OpenAPI看结构Markdown文档看细节两者配合使用。6. 我在这件事上的几点真实体会用AI辅助接口设计和异常处理这件事我做了大概三四个小项目之后有几个体会比较深。第一个体会是AI最擅长的是查漏补缺而不是从零创造。你如果自己完全没想法让AI从零设计出来的东西往往很空。但你如果已经有了一个初步方案让AI帮你找漏洞、补边界效果就非常好。所以正确的用法是自己先想一遍哪怕想得不全然后让AI在这个基础上补充。第二个体会是异常处理这件事设计阶段花的时间越多开发阶段省的时间越多。我以前总觉得小项目不用搞那么复杂异常随便处理一下就行。结果每次联调都要花大量时间处理各种边界情况反而更费时间。后来我在设计阶段就让AI帮我把异常分层和错误码定好开发阶段基本就是填空效率高了很多。第三个体会是AI生成的代码一定要自己跑一遍。我有一次直接用了AI生成的异常处理器结果发现它用的FastAPI版本和我项目里的不一样有些API已经废弃了。还有一次AI生成的CSV解析代码没有处理BOM头导致第一列字段名始终匹配不上。这些问题不跑一遍是发现不了的。最后分享一个小技巧把AI生成的接口文档和异常处理方案存到一个单独的文件里每次新项目开始的时候先把这个文件喂给AI让它基于这个模板生成新项目的方案。这样积累下来你的接口设计和异常处理会越来越规范新项目启动的速度也会越来越快。我现在已经攒了一套自己的模板覆盖了用户管理、文件上传、批量操作、第三方对接等常见场景新项目基本上改改就能用。