원클릭으로
error-handling
处理错误与异常时使用。不吞异常、不裸抛、给出可恢复信息。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
处理错误与异常时使用。不吞异常、不裸抛、给出可恢复信息。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
做 Cocos Creator 多机型/多分辨率适配时使用。Canvas、Widget、安全区。
Cocos Creator 用 AssetBundle 做分包/远程资源时使用。加载、释放、依赖、缓存。
优化 Cocos Creator 渲染性能时使用。合批、图集、动静分离、Label。
给 Cocos Creator 原生包做热更新时使用。version manifest、增量、校验、回滚。
写 Cocos Creator 动效/动画时使用。tween、Animation、Spine、性能与清理。
做 Cocos Creator 大量条目列表时使用。虚拟列表、节点复用。
| name | error-handling |
| description | 处理错误与异常时使用。不吞异常、不裸抛、给出可恢复信息。 |
| category | backend |
| tags | ["错误处理","异常"] |
console.log(e) 时。规则: catch/except 块里必须有真正的处理动作——记录日志、触发回滚、重新抛出或转换为业务错误;禁止空 catch 块,禁止仅打印后继续正常流程假装没发生过。
为什么: AI 生成代码时,"先写个 try-catch 让它跑起来"是最常见的反模式——catch (e) {} 或 except: pass。空 catch 会把真实的数据库连接失败、磁盘写入错误、第三方 API 超时全部静默吞掉,函数返回"成功",上层完全感知不到异常,日志里没有任何线索,用户看到的是数据没有保存但页面显示"操作成功"。定位这类 bug 通常要花几倍时间,因为所有的证据都被主动销毁了。
怎么做:
throw/raise),让上层决定。throw new PaymentFailedException("支付网关超时", cause=e)。finally 块做资源清理,不要把清理逻辑写在 catch 里然后 return 提前跳出。规则: 明确区分两类错误——可预期的业务错误(用户输入非法、资源不存在、权限不足)和意外的系统错误(空指针、数据库宕机、bug);前者用业务异常类表达,后者进入全局 handler 并触发告警。
为什么: AI 生成的代码经常把所有异常一律 catch (Exception e) 然后返回 500——校验失败返回 500、资源不存在返回 500、真正的 bug 也是 500。监控告警全是噪音,用户看到的错误信息毫无意义,oncall 工程师不知道哪些 500 需要紧急处理、哪些是正常的业务错误被错误分类了。错误分类是可观测性的基础,混在一起会让整个告警体系失效。
怎么做:
# 业务异常基类(可预期,映射到 4xx)
class AppError(Exception):
def __init__(self, code: str, message: str, http_status: int = 400):
self.code = code
self.message = message
self.http_status = http_status
class ResourceNotFoundError(AppError):
def __init__(self, resource: str, resource_id):
super().__init__("RESOURCE_NOT_FOUND", f"{resource} {resource_id} 不存在", 404)
# 意外错误不捕获,让全局 handler 接管,触发告警
def get_user(user_id: int) -> User:
user = db.query(User).get(user_id)
if user is None:
raise ResourceNotFoundError("User", user_id) # ✅ 业务错误,明确分类
return user
规则: 错误日志必须包含"哪个操作、哪个输入、在哪一步失败"的上下文;但对外返回的错误信息不能包含数据库表名、SQL 语句、堆栈、密钥、用户密码等敏感内容。
为什么: AI 有两种相反的倾向:要么日志只有 "操作失败" 一句话,查问题像盲人摸象;要么直接把框架抛出的原始异常(含 SQL 语句、文件路径、变量值)直接序列化返回给前端,攻击者可以从中提取数据库结构、推断内部逻辑。两种极端都在真实生产事故中反复出现。
怎么做:
logger.error("创建订单失败 user_id=%s product_id=%s amount=%s", uid, pid, amt, exc_info=True) — 带参数、带堆栈。{"code": "ORDER_CREATE_FAILED", "message": "订单创建失败,请稍后重试"} — 友好文案,无内部细节。DEBUG=False、NODE_ENV=production),避免默认暴露堆栈。1380***8888)。规则: 操作失败时必须清理已完成的副作用:回滚数据库事务、删除已创建的临时文件、释放已获取的锁、取消已发出的可撤销请求;不能让系统停留在"一半成功一半失败"的中间状态。
为什么: AI 在处理多步操作时极容易只写成功路径:第一步写数据库成功,第二步发消息失败,然后 catch 里只打了一行日志——数据库里有了这条记录,但消息没发出去,系统进入不一致状态。这类 bug 不会立刻报错,会在后续的业务流程里以奇怪的方式暴露(重复处理、数据对不上),且很难复现和修复。
怎么做:
with/using/RAII 模式,保证无论正常还是异常路径都会释放:# ✅ 正例:即使中途抛异常,文件也会被关闭
with open("report.csv", "w") as f:
write_report(f) # 若此处抛异常,with 保证 f.close() 被调用
# ❌ 反例:异常发生后 f.close() 不会执行,文件句柄泄漏
f = open("report.csv", "w")
write_report(f)
f.close()
规则: 在应用最外层(HTTP 中间件、消息消费入口、定时任务入口)设置全局异常 handler,统一兜住所有漏网异常;对用户返回固定的友好提示,同时保证完整的错误信息(含堆栈)被记录到日志系统。
为什么: AI 生成的服务代码经常没有全局兜底——未处理的异常直接导致 Node.js 进程崩溃、Python Flask 返回裸 HTML 500 页面、Go 的 panic 泄露 goroutine 堆栈给客户端。每加一个新接口都需要记住加 try-catch,一旦有人忘了,对外就是 500 裸崩。设置全局兜底等于给整个系统加了安全气囊,不依赖每个开发者都记得处理所有异常。
怎么做:
# FastAPI 全局异常处理示例
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(AppError)
async def app_error_handler(request: Request, exc: AppError):
# 业务错误:记录 warn,返回 4xx
logger.warning("业务错误 path=%s code=%s", request.url.path, exc.code)
return JSONResponse(status_code=exc.http_status,
content={"code": exc.code, "message": exc.message})
@app.exception_handler(Exception)
async def unhandled_error_handler(request: Request, exc: Exception):
# 意外错误:记录 error + 完整堆栈,触发告警,返回 500
logger.error("未捕获异常 path=%s", request.url.path, exc_info=True)
alert_oncall(exc) # 触发告警
return JSONResponse(status_code=500,
content={"code": "INTERNAL_ERROR", "message": "服务暂时异常,请稍后重试"})
# 反例 — 吞掉了数据库异常,函数返回 None 假装成功
def save_order(order: Order) -> bool:
try:
db.session.add(order)
db.session.commit()
return True
except Exception:
pass # ❌ 什么都没做:日志没有,回滚没有,调用方不知道失败了
return False # 调用方收到 False 但不知道是哪类错误,也没法重试
# 调用方
if not save_order(order):
print("保存失败") # ❌ 但没有任何错误信息可以定位问题
# 正例 — 明确回滚 + 记录 + 重抛
def save_order(order: Order) -> None:
try:
db.session.add(order)
db.session.commit()
except SQLAlchemyError as e:
db.session.rollback() # ✅ 清理:回滚事务
logger.error("保存订单失败 order_id=%s", order.id, exc_info=True) # ✅ 记录完整堆栈
raise OrderPersistenceError("订单保存失败") from e # ✅ 转换语义后重抛
# 反例 — 内部 SQL 错误暴露给客户端
@app.route("/users/<int:user_id>")
def get_user(user_id):
try:
return jsonify(db.get_user(user_id))
except Exception as e:
return jsonify({"error": str(e)}), 500
# ❌ str(e) 可能包含:
# "column 'passwrd' does not exist in table 'users'"
# 暴露了表名、字段名,攻击者可以利用这些信息
# 正例 — 内外信息分离
@app.route("/users/<int:user_id>")
def get_user(user_id):
try:
return jsonify(db.get_user(user_id))
except ResourceNotFoundError as e:
return jsonify({"code": e.code, "message": e.message}), 404 # ✅ 业务错误,友好提示
except Exception as e:
logger.error("获取用户失败 user_id=%s", user_id, exc_info=True) # ✅ 完整堆栈写日志
return jsonify({"code": "INTERNAL_ERROR", "message": "服务异常"}), 500 # ✅ 对外不暴露细节
with/using/RAII 模式管理,异常路径也能保证释放。