最稳方案是直接用curl_exec()并确保curl扩展启用;TP不干涉HTTP请求,需自行处理SSL、超时、JSON解析、签名验签等细节,避免硬编码和中间件干扰回调。

ThinkPHP里直接用curl_exec()最稳
别一上来就封装类或装Guzzle,很多TP项目连curl扩展都没开,先确保底层能通。TP本身不干涉HTTP请求,它只管路由和响应输出,真正发请求还得靠PHP原生能力。
常见错误是控制器里写file_get_contents()调HTTPS接口,结果报SSL operation failed——这不是TP的问题,是PHP没配CA证书路径,也压根没开openssl扩展。
- 先执行
extension_loaded('curl')检查扩展是否启用,没启用就去php.ini开extension=curl - TP6默认关闭
allow_url_fopen,所以file_get_contents()在多数生产环境根本不能用,别试 - 发POST时别传数组给
CURLOPT_POSTFIELDS,必须json_encode($data)再设Content-Type: application/json头,否则对方收不到字段 - 一定要加
CURLOPT_TIMEOUT => 15,TP的App::run()默认超时是30秒,但第三方API卡住会拖垮整个请求生命周期
在TP6里封装一个WingPayClient类
对接翼支付这类有固定参数结构、需签名、带token刷新逻辑的API,硬编码在控制器里迟早出事。但也不用照搬Laravel的服务容器那一套,TP6够轻量,直接建app/common/client/WingPayClient.php就行。
关键不是“怎么封装”,而是“哪些东西必须抽出来”:商户ID、密钥、网关域名、签名算法、token缓存方式。这些全塞进config/wingpay.php,而不是写死在类里。
立即学习“PHP免费学习笔记(深入)”;
-
getAccessToken()方法里别每次请求都重取token,查缓存(可用TP自带的cache());过期才重刷,并原子化更新,避免并发重复刷新 - 构造签名时注意翼支付要求参数按字典序拼接+MD5,别漏掉空值字段或错位排序,调试时把原始字符串打日志,比对着文档逐字符核对
- 回调通知地址必须是公网可访问的完整URL(如
https://yourdomain.com/api/wingpay/notify),TP6的Route::miss()或中间件拦截会导致验签失败后直接404,翼支付就认为你没收到
别在控制器里手动解析JSON响应
TP6的think\Http类已经内置了json()方法,但那是给返回JSON响应用的;你调第三方API时,拿到的是原始$response字符串,直接json_decode($response, true)就行,别绕到Response::create()再转一圈。
容易踩的坑是忽略HTTP状态码。翼支付返回200不代表支付成功,它可能返回{"code":4001,"msg":"订单已存在"}——这个code是业务码,得从响应体里读,不是curl_getinfo($ch, CURLINFO_HTTP_CODE)。
- 必须检查
curl_errno($ch),为0才说明网络层成功;非0就得记录curl_error($ch),比如Could not resolve host这种DNS问题,TP日志里看不到,只能靠这句 - 用
json_last_error()判断json_decode()是否失败,有些API返回HTML错误页(比如Nginx 502),json_decode()会静默返回null,你不校验就直接isset($res['data'])会报Notice - 翼支付的
createorder接口若返回sign_error,90%是时间戳没用UTC+0、或签名原文里混入了不可见空格,建议把待签名字符串先trim()再md5()
回调通知必须走独立入口,禁用CSRF和中间件
微信小程序调翼支付,支付完成后翼支付服务器会POST数据到你填的notify URL。这个请求不是用户浏览器发起的,是翼支付服务端直连,所以TP6默认开启的VerifyToken中间件、CheckRequestCache、甚至SessionInit都得关掉,否则token mismatch或session_start(): Cannot send session cache limiter直接让回调失败。
最简单的做法是在route/app.php里单独注册一条不走中间件的路由:
Route::post('api/wingpay/notify', 'api.WingPay/notify')->middleware([]);
然后在app/api/controller/WingPay.php的notify()方法开头就做三件事:关闭session、设置input()为原始POST、立即验签。
- 别用
$this->request->param(),它会自动过滤和转换,翼支付的签名原文必须原样参与验签 - 验签失败必须返回
success字符串(翼支付要求),不是JSON,不是200 OK,就纯文本success,多一个空格都不行 - 处理成功后记得
return json(['code' => 0, 'msg' => 'ok']),但这是给TP自己看的,翼支付只认第一行输出



















