PHP 集成 WePay payment gateway 时 checkout 页面空白
结论
checkout 页面空白,通常不是 WePay 没有返回页面,而是 PHP 在创建 checkout 时出错,同时服务器关闭了错误显示。正确的处理流程是:调用 /checkout/create``,读取 WePay 返回的 checkout_uri`,然后将浏览器重定向到这个地址。
先查看 PHP 错误日志和 WePay API 的原始响应。不要直接输出可能不存在的 checkout_uri,也不要把 WePay 支付页的源码当作本地页面渲染。
先让错误可见
在测试环境中临时开启错误报告:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
生产环境不要向访客显示错误,只将错误写入日志:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '0');
ini_set('log_errors', '1');
同时检查 Web 服务器和 PHP-FPM 的错误日志。空白页通常由以下问题引起:
- SDK 文件未正确加载;
- PHP 命名空间或类名有误;
- cURL、OpenSSL 等扩展未启用;
access_token或account_id无效;- 混用了 sandbox 凭据和 production 环境;
- API 返回了错误对象,但代码仍继续读取
checkout_uri; header()执行前已经产生输出;- 异常未被捕获。
正确创建并跳转到 checkout
下面的示例适用于使用经典 /checkout/create 接口的 WePay PHP SDK。不同版本的 SDK 可能有不同的初始化方法和返回值类型,请以所用 SDK 的代码及配套文档为准。
<?php
require_once __DIR__ . '/wepay.php';
error_reporting(E_ALL);
ini_set('display_errors', '1');
$clientId = getenv('WEPAY_CLIENT_ID');
$clientSecret = getenv('WEPAY_CLIENT_SECRET');
$accessToken = getenv('WEPAY_ACCESS_TOKEN');
$accountId = getenv('WEPAY_ACCOUNT_ID');
try {
// 测试环境。正式上线时改用对应的 production 初始化方法。
WePay::useStaging($clientId, $clientSecret);
$wepay = new WePay($accessToken);
$response = $wepay->request('/checkout/create', [
'account_id' => $accountId,
'amount' => 10.00,
'short_description' => 'Order #1001',
'type' => 'GOODS',
'redirect_uri' => 'https://example.com/payment/return.php',
]);
// SDK 可能返回对象,也可能返回数组。
$checkoutUri = is_array($response)
? ($response['checkout_uri'] ?? null)
: ($response->checkout_uri ?? null);
if (!$checkoutUri) {
throw new RuntimeException(
'WePay response does not contain checkout_uri: ' .
json_encode($response, JSON_UNESCAPED_UNICODE)
);
}
header('Location: ' . $checkoutUri, true, 302);
exit;
} catch (Throwable $e) {
error_log('WePay checkout error: ' . $e->getMessage());
http_response_code(500);
// 测试环境可以显示详细错误,生产环境应改成通用提示。
echo '无法创建支付页面:' .
htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
}
如果项目仍使用不支持 Throwable 的旧版 PHP,可以改为:
catch (Exception $e) {
// ...
}
旧版 PHP 已经存在安全和兼容风险,应优先升级。
检查 API 的实际返回值
调试时不要假设请求一定成功,可以暂时输出返回结果:
echo '<pre>';
var_dump($response);
echo '</pre>';
exit;
成功响应中应包含用于跳转的 checkout_uri。如果 API 返回错误信息,需要检查:
error;error_code;error_description;- HTTP 状态码;
account_id是否属于当前access_token;- 请求字段是否符合当前 API 版本的要求。
记录响应时,应遮盖 access_token、client_secret、银行卡信息和其他敏感数据。
排查重定向问题
如果已经取得 checkout_uri,浏览器却没有跳转,请检查 header() 之前是否产生了任何输出,包括空格、BOM、调试文本和模板内容。
if (headers_sent($file, $line)) {
throw new RuntimeException(
"HTTP headers already sent in {$file} on line {$line}"
);
}
纯 PHP 文件通常不需要在末尾添加 ?>,这样可以避免文件末尾的空白提前发送响应头。
也可以直接查看跳转地址:
var_dump($checkoutUri);
exit;
如果这个地址可以在浏览器中直接打开,问题通常出在本地重定向逻辑。如果地址为空,则需要继续检查 /checkout/create 的响应。
环境与服务器检查
确认 PHP 已加载必要的扩展:
<?php
var_dump([
'curl' => extension_loaded('curl'),
'openssl' => extension_loaded('openssl'),
'json' => extension_loaded('json'),
]);
还需要确认:
- 服务器可以通过 HTTPS 访问 WePay API;
- CA 证书有效,不要关闭 SSL 校验来绕过证书错误;
- staging 使用测试凭据,production 使用正式凭据;
redirect_uri是完整 URL;- 服务器时间准确;
- PHP 和 Web 服务器的日志目录可写。
不要直接嵌入未知的 checkout 页面
应优先将浏览器重定向到 WePay 返回的 checkout_uri。如果使用 iframe 加载,浏览器安全策略或 WePay 页面的响应头可能会阻止页面,导致页面空白或无法加载。
如果当前 WePay 产品使用 JavaScript checkout、合作伙伴接口或其他新版流程,就不能直接照搬旧版 /checkout/create 示例。此时需要根据账户类型、SDK 版本和对应的 API 文档调整请求方式。排查步骤仍然相同:先捕获 PHP 错误,再检查 API 响应,取得有效的支付地址后再执行跳转。
备注:内容仅供参考。
