/** * 标品PP 真实接口调试脚本(从 DB 读取完整数据) * 使用租户 id=5 (名称:895) + 接口 id=4 (标品部门数据) */ const crypto = require('crypto'); const axios = require('axios'); const db = require('../db'); // ─── 工具函数 ───────────────────────────────────────────────────────────── /** * 将私钥(多种格式)解析为 Node.js crypto 可用的 KeyObject * 支持: * - 裸 base64 PKCS8 DER(Java 导出格式) * - PEM 格式 */ function loadPrivateKey(raw) { if (raw.includes('-----BEGIN')) { return crypto.createPrivateKey(raw); } const derBuf = Buffer.from(raw.trim(), 'base64'); return crypto.createPrivateKey({ key: derBuf, format: 'der', type: 'pkcs8' }); } function generateNonce(length = 8) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); } function generateSign(params, privateKey) { const sortedKeys = Object.keys(params).sort(); const signString = sortedKeys.map(k => `${k}=${params[k]}`).join('&'); console.log('[签名] 待签名字符串:', signString); const signer = crypto.createSign('RSA-MD5'); signer.update(signString, 'utf8'); const signature = signer.sign(privateKey, 'base64'); console.log('[签名] Base64 (前30):', signature.substring(0, 30) + '...'); return signature; } // ─── 主流程 ──────────────────────────────────────────────────────────────── async function main() { console.log('='.repeat(60)); console.log('标品PP 真实接口调试:标品部门数据'); console.log('='.repeat(60)); // 从 DB 读取完整数据 const [[tenant]] = await db.query('SELECT * FROM tenants WHERE id = ?', [5]); const [[endpoint]] = await db.query('SELECT * FROM endpoints WHERE id = ?', [4]); if (!tenant || !endpoint) { console.error('❌ 租户或接口不存在'); process.exit(1); } console.log('\n[租户] 名称:', tenant.name, '| 类型:', tenant.type); console.log('[接口] 名称:', endpoint.name, '| URL:', endpoint.url); console.log('[私钥] 长度:', tenant.private_key?.length, '字符'); // 1. 加载私钥 let privateKey; try { privateKey = loadPrivateKey(tenant.private_key); console.log('✅ 私钥加载成功(类型:', privateKey.asymmetricKeyType, ')'); } catch (e) { console.error('❌ 私钥加载失败:', e.message); // 尝试输出私钥前后片段以诊断 console.log(' 私钥开头:', tenant.private_key.substring(0, 50)); console.log(' 私钥结尾:', tenant.private_key.slice(-50)); process.exit(1); } // 2. 构建 query 参数(不含 sign) const params = { entCode: tenant.ent_code, apiCode: endpoint.api_code, timestamp: Date.now().toString(), nonce: generateNonce(8), }; console.log('\n[参数] 基础参数:', JSON.stringify(params)); // 3. 生成签名 let signature; try { signature = generateSign(params, privateKey); params.sign = signature; console.log('✅ 签名生成成功'); } catch (e) { console.error('❌ 签名失败:', e.message); process.exit(1); } // 4. 构建请求 const encodedKey = Buffer.from(`${tenant.api_key}:`).toString('base64'); const headers = { 'Authorization': `Basic ${encodedKey}`, 'Content-Type': 'application/json', }; const body = JSON.parse(endpoint.body || '{}'); // 5. CURL 命令 const urlObj = new URL(endpoint.url); Object.entries(params).forEach(([k, v]) => urlObj.searchParams.set(k, v)); let curlCmd = `curl -X ${endpoint.method} '${urlObj.toString()}'`; Object.entries(headers).forEach(([k, v]) => { curlCmd += ` \\\n -H '${k}: ${v}'`; }); curlCmd += ` \\\n -d '${JSON.stringify(body)}'`; console.log('\n[CURL]\n' + curlCmd); // 6. 发送请求 console.log('\n[请求] 发送中...'); try { const response = await axios({ method: endpoint.method.toLowerCase(), url: endpoint.url, headers, params, data: body, timeout: 15000, }); console.log('\n✅ 请求成功!'); console.log('[响应] 状态:', response.status); console.log('[响应] 数据:'); console.log(JSON.stringify(response.data, null, 2).substring(0, 1000)); } catch (err) { console.error('\n❌ 请求失败!'); if (err.response) { console.error('[错误] HTTP 状态:', err.response.status); console.error('[错误] 响应:', JSON.stringify(err.response.data, null, 2)); } else { console.error('[错误]', err.message); } } process.exit(0); } main().catch(e => { console.error(e); process.exit(1); });