首先交代一下本人遇到 “Http头缺少Accept或User-Agent” 报错的情况:

开发语言:PHP
微信 SDK 版本:无
报错 API:创建支付分订单API

接手项目中并未使用微信 SDK v2 或者最新的 v3,而是使用 CURL 直接构造 clent 请求,请求参数还是 xml 格式(感觉比较古老)。因为微信支付等主要功能都还可以使用,所以暂未考虑使用最新版本的 SDK v3。而微信支付分属于新增接口(估计之前项目开发时微信都没有这个功能),所以新接口直接使用了 微信支付分 v3 版本接口

在构建好创建支付分订单的请求后,发现返回参数报错 “Http头缺少Accept或User-Agent”。参考了 wechatpay-php/src/ClientXmlTrait.php$headers 的写法:

    protected static $headers = [
        'Accept' => 'text/xml, text/plain, application/x-gzip',
        'Content-Type' => 'text/xml; charset=utf-8',
    ];

请求依然报错。

百度找到一篇 微信开放社区 里的问答文档,有位 PHPer 提到 AcceptUser-Agent 与冒号之间不能有空格。这个检查过了,没有问题。然后突然意识到,他的代码截图有些不一样,形式如下:

    $headers = [
        'Accept: text/xml, text/plain, application/x-gzip',
        'Content-Type: text/xml; charset=utf-8',
    ];

然后记忆突然就回来了,之前也曾遇到过相同的情况。PHP curl 请求参数设置 curl_setopt($curl,CURLOPT_HTTPHEADER, $headers); 中的 $headers 应该是数值数组,也就是最普通的数组,而非关联数组。这点在 curl_setopt - php.net 文档中有示例说明:

CURLOPT_HTTPHEADER 可选 value 值
CURLOPT_HTTPHEADER 可选 value 值

原本以为到这就结束了,谁知提交后又报了新的错误:“Http头Accept值必须为application/json或/”、“Http头Content-Type值必须为application/json”,以及 “Http头Authorization值格式错误,请参考《微信支付商户REST API签名规则》”。

得了,也就是说,在这个支付分的新接口上微信现在就只接收和返回 json 格式的数据了。这样也好,对于多维数组的数据,构建 xml 字符串还不如 json 来的直观,请求参数和返回值也不用再来回转换了。

关于 “Http头Authorization值格式错误,请参考《微信支付商户REST API签名规则》” 在这里不再展开讨论,这涉及到微信 SDk v3 版本的 签名生成 方式,建议参考微信官方文档,或直接使用微信 SDK v3,内部封装非常好(有些看不懂的 PHP 高级特性)。

最终的 $headers

    $headers = [
        'Authorization:' . $schema . ' ' . $token,
        'Accept: application/json',
        'Content-Type: application/json; charset=utf-8',
        'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
    ];

User-Agent 参数内容不重要,但微信规定必须得有。