需用 cURL 显式设置 JSON 头、Bearer 授权及 Vivo 签名头;签名须按 timestamp、nonce、app_key、原始 JSON body 拼接后 HMAC-SHA256 加密;timestamp 为秒级且偏差≤300秒;access_token 应缓存于 APCu/Redis 并带过期时间,避免硬编码或频繁重取。

怎么用 PHP 发起 vivo 内容生态 API 的 POST 请求
vivo 内容生态 API(如内容推荐接口)要求使用 POST 方法、application/json 格式提交,并携带有效签名和 access_token。PHP 默认的 file_get_contents() 不带请求体或头控制,直接调用会返回 {"code":4001,"msg":"invalid sign"} 或 401 Unauthorized。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
curl_init()显式设置Content-Type: application/json和Authorization: Bearer {token} - 签名必须按文档拼接字段(含
timestamp、nonce、app_key、body的原始 JSON 字符串),再用hash_hmac('sha256', $str, $app_secret)计算,不能对 body 先json_encode()再 decode 二次处理 -
timestamp必须是秒级 Unix 时间戳,且与 vivo 服务器时间差不能超过 300 秒,否则返回{"code":4003,"msg":"timestamp invalid"} - 示例关键片段:
$ch = curl_init('https://api.vivo.com.cn/recommend/v1/items'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: Bearer ' . $access_token, 'X-Vivo-Sign: ' . $sign, 'X-Vivo-Timestamp: ' . $timestamp, 'X-Vivo-Nonce: ' . $nonce ]);
PHP 如何安全存储和刷新 vivo access_token
access_token 由 /auth/token 接口颁发,有效期 2 小时,过期后所有推荐请求都会返回 401。它不是长期凭证,不能硬编码在配置里,也不能每次请求都重新获取。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 把
access_token+expires_in+timestamp存进本地apcu或 Redis,键名用vivo:token:{app_key},避免多进程重复刷新 - 每次调用前先查缓存,若剩余有效期 curl_exec() 非阻塞调用)刷新,不阻塞主请求流
- 注意:vivo 的 token 接口要求
client_id和client_secret做 Basic Auth,PHP 中要用base64_encode("{$client_id}:{$client_secret}")构造Authorization: Basic xxx
为什么 vivo 推荐接口返回空数组或 code=20001
常见现象是请求成功(HTTP 200)、code 却为 20001,文档写的是“参数错误”,但实际原因往往更具体:用户设备信息缺失、位置参数格式不对、或 scene 值未按白名单填写。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
-
scene必须是 vivo 文档明确列出的值,比如"home_feed"、"search_result",传"homepage"或空字符串会触发该错误 - 如果传了
location,必须是标准 WGS84 坐标,且lat/lng是 float 类型数字,字符串如"39.9"会被拒绝 - 调试时打开
error_log(json_encode($response), 3, '/tmp/vivo.log'),确认响应里trace_id是否存在——有则说明请求已进 vivo 网关,问题出在业务校验;无则可能是网络或签名层拦截
PHP 处理 vivo 返回的 UTF-8 中文乱码问题
vivo API 返回的 JSON 默认是 UTF-8 编码,但部分老版本 PHP(如 7.0 以下)在用 json_decode() 解析含中文的响应时,若没显式指定第二个参数为 true,且原字符串含 BOM 或换行符,可能解析失败或字段丢失。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 始终用
json_decode($raw_response, true, 512, JSON_UNESCAPED_UNICODE),其中JSON_UNESCAPED_UNICODE防止中文被转成\uXXXX - 收到响应后先检查
mb_detect_encoding($raw_response)是否为UTF-8,不是则用mb_convert_encoding($raw_response, 'UTF-8', 'GBK')转换(极少数安卓低版本客户端可能误报编码) - 不要依赖
header('Content-Type: text/html; charset=utf-8')来“修复” JSON 解析——那是输出层的事,跟json_decode无关
签名生成逻辑和 timestamp 同步是整个链路最易出错的环节,哪怕其他都对,差 1 秒或少拼一个字段,vivo 就只回 4001,不提示具体哪错了。



















