# 甘草 API "Array to string conversion" 最终修复 ## 问题根源 错误发生在 `GancaoScmRecipelService::getToken()` 方法中: ```php // 第 126 行 if ($code === '10103' || str_contains($apiMsg, '10103')) { ``` **原因:** 当甘草 API 返回错误时,`$body['status']['msg']` 可能是**数组**而不是字符串,导致: 1. `apiStatusMessage()` 方法尝试将数组转换为字符串 2. `str_contains()` 函数接收到数组参数,触发 "Array to string conversion" 错误 ## 已修复的问题 ### 1. `apiStatusMessage()` 方法 **修复前:** ```php $msg = (string) ($body['status']['msg'] ?? ''); ``` **修复后:** ```php $msg = $body['status']['msg'] ?? ''; // 确保 msg 是字符串 if (is_array($msg)) { $msg = json_encode($msg, JSON_UNESCAPED_UNICODE); } else { $msg = (string) $msg; } ``` ### 2. `getToken()` 方法中的 `str_contains()` 调用 **修复前:** ```php if ($code === '10103' || str_contains($apiMsg, '10103')) { ``` **修复后:** ```php // 确保 $apiMsg 是字符串,避免 Array to string conversion 错误 $apiMsgStr = is_string($apiMsg) ? $apiMsg : json_encode($apiMsg, JSON_UNESCAPED_UNICODE); if ($code === '10103' || str_contains($apiMsgStr, '10103')) { ``` ### 3. 其他已修复的问题 #### SSL 连接问题(`GancaoOpenApiTransport.php`) - ✅ 改用 HTTP/1.1 - ✅ 强制使用 TLS 1.2 - ✅ 降低 OpenSSL 安全级别 - ✅ 增加连接超时 - ✅ 添加 TCP keepalive #### 配置类型问题(`GancaoScmRecipelService.php`) - ✅ 确保 `express_type` 是字符串 - ✅ 确保 `callback_url` 是字符串 - ✅ 修复患者年龄格式 - ✅ 优化 `doct_advice` 字段处理 #### 错误处理(`PrescriptionOrderLogic.php` 和 `PrescriptionOrderController.php`) - ✅ 添加详细错误日志 - ✅ 添加异常捕获 - ✅ 添加返回值类型检查 ## 完整的修复文件列表 1. ✅ `server/app/common/service/gancao/GancaoScmRecipelService.php` 2. ✅ `server/app/common/service/gancao/GancaoOpenApiTransport.php` 3. ✅ `server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php` 4. ✅ `server/app/adminapi/controller/tcm/PrescriptionOrderController.php` ## 部署步骤 ### 步骤 1: 上传所有修复文件 ```bash # 上传修复后的文件 scp server/app/common/service/gancao/GancaoScmRecipelService.php user@server:/path/to/server/app/common/service/gancao/ scp server/app/common/service/gancao/GancaoOpenApiTransport.php user@server:/path/to/server/app/common/service/gancao/ scp server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php user@server:/path/to/server/app/adminapi/logic/tcm/ scp server/app/adminapi/controller/tcm/PrescriptionOrderController.php user@server:/path/to/server/app/adminapi/controller/tcm/ # 上传测试脚本 scp test_gancao_config.php user@server:/path/to/ scp test_gancao_ssl.php user@server:/path/to/ scp diagnose_gancao_payload.php user@server:/path/to/ ``` ### 步骤 2: 验证文件已上传 ```bash ssh user@server cd /path/to/your/project # 检查文件修改时间 ls -la server/app/common/service/gancao/GancaoScmRecipelService.php ls -la server/app/common/service/gancao/GancaoOpenApiTransport.php ls -la server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php ls -la server/app/adminapi/controller/tcm/PrescriptionOrderController.php ``` ### 步骤 3: 运行配置检查 ```bash php test_gancao_config.php ``` **期望输出:** 所有配置项显示 ✓ ### 步骤 4: 运行 SSL 测试 ```bash php test_gancao_ssl.php ``` **期望输出:** 至少一种 SSL 配置测试成功,并且能成功获取 token ### 步骤 5: 清除缓存 ```bash cd server php think clear rm -rf runtime/cache/* rm -rf runtime/temp/* ``` ### 步骤 6: 重启服务 ```bash # PHP-FPM sudo systemctl restart php-fpm # Nginx sudo systemctl restart nginx # 或者 Apache sudo systemctl restart apache2 ``` ### 步骤 7: 测试接口 **开启日志监控:** ```bash tail -f server/runtime/log/$(date +%Y%m%d).log | grep -E "(Gancao|gancao|submitGancao)" ``` **在另一个终端调用接口:** ```bash curl -X POST https://your-domain.com/api/tcm.prescriptionOrder/submitGancaoRecipel \ -H "Content-Type: application/json" \ -H "token: your_admin_token" \ -d '{"id": 订单ID}' ``` ## 预期结果 ### 成功的情况 **接口响应:** ```json { "code": 1, "show": 0, "msg": "甘草药方上传成功", "data": { "recipel_order_no": "GC202604...", "app_order_no": "PO123", "fee": { "total": 150.00, "medicine": 120.00, "process": 20.00, "express": 10.00 } } } ``` **日志内容:** ``` [info] Gancao MAKE_TOKEN request: {...} [info] Gancao MAKE_TOKEN response: {...} [info] Gancao CTM_SUBMIT_RECIPEL payload: {...} [info] submitGancaoRecipel success: {...} ``` **数据库变化:** - `prescription_order` 表中对应订单的 `gancao_reciperl_order_no` 字段已更新 - `gancao_submit_time` 字段已更新为当前时间戳 ### 失败的情况 如果仍然失败,日志会显示详细错误信息: **配置错误:** ``` [error] Gancao MAKE_TOKEN api error: {"body": {...}, "apiMsg": "..."} ``` → 检查 `.env` 配置,特别是 AK/SK **SSL 连接错误:** ``` [error] Gancao CTM_SUBMIT failed: {"subRet": {...}, "payload": {...}} ``` → 运行 `php test_gancao_ssl.php` 诊断 SSL 问题 **业务逻辑错误:** ``` [error] submitGancaoRecipel exception: {"message": "...", "trace": "..."} ``` → 检查处方数据是否完整,药材 ID 是否正确映射 ## 常见错误和解决方案 ### 错误 1: "Array to string conversion" **已修复!** 如果仍然出现,请检查: 1. 文件是否正确上传 2. 缓存是否已清除 3. 服务是否已重启 ### 错误 2: SSL 连接错误 **解决方案:** 1. 运行 `php test_gancao_ssl.php` 2. 查看哪种 SSL 配置成功 3. 如果都失败,检查 OpenSSL 版本:`openssl version` 4. 联系甘草技术支持确认 SSL 要求 ### 错误 3: "MAKE_TOKEN 失败:[10103]" **原因:** AK/SK 不匹配或密码计算错误 **解决方案:** 1. 检查 `.env` 中的配置: ```env GANCAO_SCM_BIZ_AK=xxx GANCAO_SCM_BIZ_SK=xxx ``` 2. 确认 BIZ AK/SK 与网关 AK/SK 是否相同 3. 检查服务器时间是否正确:`date` 4. 联系甘草获取正确的 AK/SK ### 错误 4: "药材无法匹配甘草药ID" **原因:** 药材 ID 映射缺失 **解决方案:** 1. 检查 `zyt_doctor_medicine` 表中药材的 `gid` 字段 2. 或在 `.env` 配置 `herb_id_map`: ```php 'herb_id_map' => [ '当归' => 1001, '黄芪' => 1002, ] ``` ## 验证修复成功 ✅ **所有以下条件都满足,说明修复成功:** 1. `php test_gancao_config.php` 全部通过 2. `php test_gancao_ssl.php` 显示 "✓ 成功获取 token" 3. 接口返回 `{"code": 1, "msg": "甘草药方上传成功"}` 4. 日志中显示 `submitGancaoRecipel success` 5. 数据库中订单已更新 `gancao_reciperl_order_no` 6. 没有 "Array to string conversion" 错误 7. 没有 SSL 连接错误 ## 技术支持 如果以上步骤都无法解决问题,请收集以下信息: 1. **配置检查输出:** ```bash php test_gancao_config.php > config_check.txt 2>&1 ``` 2. **SSL 测试输出:** ```bash php test_gancao_ssl.php > ssl_check.txt 2>&1 ``` 3. **错误日志:** ```bash tail -200 server/runtime/log/$(date +%Y%m%d).log > error.log ``` 4. **接口响应:** ```bash curl -X POST ... > response.json 2>&1 ``` 5. **系统信息:** ```bash php -v > system_info.txt openssl version >> system_info.txt curl --version >> system_info.txt cat /etc/os-release >> system_info.txt ``` 将这些文件发送给技术支持进行分析。 ## 总结 这次修复解决了三个主要问题: 1. **Array to string conversion** - 甘草 API 返回的错误消息可能是数组 2. **SSL 连接失败** - TLS 版本和 HTTP 版本不兼容 3. **配置类型错误** - 某些配置值被错误地解析为数组 所有问题都已修复,现在应该可以正常调用甘草 API 了!