应先用qimage加载图片并保存为标准jpeg再base64编码,去除data:前缀且校验长度;启动时获取access_token并缓存至本地,每次请求前检查有效期,避免频繁刷新。

直接用 QNetworkAccessManager 发 POST 请求就行,但关键不是“能不能发”,而是“发什么、怎么编码、怎么防错”。百度AI人脸识别接口对请求体格式、图片编码方式、token 有效期、错误码含义都卡得很细,稍不注意就返回 {"error_code":17,"error_msg":"access_token invalid or no longer valid"} 或 {"error_code":222201,"error_msg":"image format error"} 这类模糊提示。
怎么构造合法的 base64 图片字段
百度要求图片必须是 base64 编码后的字符串,且不能带 data:image/jpeg;base64, 前缀——这是微信小程序里常见的写法,但在百度 API 里会直接报 image format error。
- Qt 里用
QImage读图后转成QByteArray,再调用.toBase64(),结果是纯 base64 字符串(如/9j/4AAQSkZJR...) - 别用
QFile::readAll()直接读 JPEG 文件再 base64——某些摄像头保存的 JPEG 可能含非标准 marker,导致百度解析失败;建议先用QImage::save()过一遍再编码 - 上传前务必检查长度:
base64.length() % 4 == 0,否则 token 解析会静默失败
access_token 怎么管才不会过期失效
access_token 有效期只有 30 天,但实际调用中更常遇到的是“1天内多次获取导致配额超限”或“没缓存 token 导致每次请求都先去换 token,拖慢响应”。
- 不要在每次识别前都调一次
https://aip.baidubce.com/oauth/2.0/token;应该在程序启动时获取并缓存到本地文件(如token.json),同时记录expires_in时间戳 - 每次发识别请求前,检查缓存 token 的剩余有效期是否
- 刷新失败时要有 fallback:比如降级为本地人脸框检测(用
cv::CascadeClassifier或虹软轻量版 SDK),避免整个功能不可用
POST 请求体里哪些字段不能少、不能错
以 /rest/2.0/face/v3/detect 为例,最简可用的 JSON body 长这样:
{
"image": "xxx",
"image_type": "BASE64",
"face_field": "faceshape,landmark"
}
注意几个硬约束:
-
image_type必须是字符串"BASE64"(全大写),写成"base64"或base64都会返回error_code: 222202 -
face_field是可选字段,但如果传了就必须是百度文档里明确列出的字段名组合,多一个空格或拼错一个字母(如"landmark72"写成"landmark73")就会整体忽略该字段,不报错但也不返回 - 所有字段名必须小写,
Image或IMAGE_TYPE会导致 400 - 如果走人脸搜索(
/v3/search),group_id必须和你在百度智能云后台创建的人脸库 ID 完全一致(区分大小写、不能有空格)
收到 JSON 响应后怎么安全解析
百度返回的 JSON 结构不稳定:成功时有 result 字段,失败时只有 error_code 和 error_msg,而且某些错误(如配额超限)会返回 HTTP 200 + 错误体,不能只靠 status code 判断。
- 永远先检查
jsonObject.contains("error_code"),再决定走 success 还是 error 分支 -
result是对象还是数组取决于接口:detect 接口的result是对象,search 接口的result是数组,强行用toObject()会 crash - 用
QJsonParseError检查原始响应是否为合法 JSON——网络中断、代理截断、HTTPS 证书异常都可能导致返回 HTML 或空响应 - 别信
result.face_num的值:它只是检测到的框数,不代表质量合格;真正要用于业务逻辑的,是result.face_list[0].face_token和result.face_list[0].quality里的子字段
最常被忽略的一点:百度 API 的 timeout 默认是 60 秒,但 Qt 的 QNetworkRequest 默认没有设 timeout。一旦网络抖动或百度服务端卡住,你的 UI 线程可能假死几十秒——必须显式调用 request.setAttribute(QNetworkRequest::HttpTimeoutAttribute, 10000) 设为 10 秒,并在槽函数里检查 reply->error() != QNetworkReply::NoError。











