日志表里存了上游响应原文。某天查询接口开始 500:
sqlite3.OperationalError: Could not decode to UTF-8
而且是偶发的——查某些行没事,查另一些就炸。我一开始盯着 SQL 改了半天,后来才反应过来:只有部分数据能触发,问题在内容,不在语句。
SQLite 的 TEXT 列不强制校验编码。写入方把非 UTF-8 的字节流(压缩过的响应体、图片二进制、其他编码的文本)原样塞进去,写入时不会报错。但 Python 的 sqlite3 默认以 text_factory = str 读取,碰到非法字节就直接抛异常。
所以问题不在查询那一刻,在写入那一刻。
拿到连接后覆盖 text_factory,用 replace 把解不出的字节换掉,查询就不会再因为编码中断:
conn = sqlite3.connect(db_path)
conn.text_factory = lambda b: b.decode("utf-8", "replace")
这行是兜底,代价是损坏的字节会变成替换字符,但接口不会再 500。日志、监控这种"看个大概就行"的场景,够了。
真正该动手的地方是数据入口:
text.encode("utf-8", "replace").decode("utf-8");BLOB 列存 bytes,别塞进 TEXT;临时按字节读出来看:
conn.text_factory = bytes
row = conn.execute("SELECT content FROM logs WHERE id = ?", (bad_id,)).fetchone()
print(row[0][:200])
前面几十个字节基本就能看出是什么东西。读取侧加容错、写入侧做归一化,两头都得有——只做一头,迟早还会遇到。