Jazzcash支付网关集成中pp_SecureHash无效问题求助
JazzCash支付网关集成问题排查(NestJS)
问题代码
import axios from 'axios'; import crypto from 'crypto'; async initiatePayment( amount: number, billReference: string, description: string, ) { const txnRefNo = `T${Date.now()}`; const txnDateTime = new Date() .toISOString() .slice(0, 19) .replace(/[-:T]/g, ''); const txnExpiry = txnDateTime; // For sandbox, same as txnDateTime const payload: Record<string, any> = { pp_Version: '1.1', pp_TxnType: 'MPAY', pp_TxnRefNo: txnRefNo, pp_MerchantID: this.merchantId, pp_Password: this.password, pp_Amount: amount.toString(), pp_TxnCurrency: 'PKR', pp_TxnDateTime: txnDateTime, pp_TxnExpiryDateTime: txnExpiry, pp_BillReference: billReference, pp_Description: description, pp_CustomerCardNumber: 5123450000000008, pp_UsageMode: 'API', }; // Generate secure hash payload.pp_SecureHash = this.generateSecureHash(payload); try { console.log('payload:', payload); const response = await axios.post(this.baseUrl, payload); console.log('response.data:', response.data); return response.data; // JazzCash response } catch (err) { console.error('JazzCash API error:', err.response?.data || err.message); throw err; } } private generateSecureHash(payload: Record<string, any>): string { const sortedKeys = Object.keys(payload) .filter((k) => payload[k] !== undefined && payload[k] !== '') .sort(); const dataString = sortedKeys.map((k) => `${k}=${payload[k]}`).join('&'); const hash1 = crypto .createHash('sha256') .update(this.integritySalt + dataString) .digest('hex') .toUpperCase(); const hash2 = crypto.createHash('sha256').update(dataString).digest('hex'); const key = new Buffer('hi', 'hex'); const hash4 = crypto .createHmac('sha256', key) .update(dataString) .digest('hex'); const hash5 = crypto.createHash('sha256').update(dataString).digest('hex'); console.log('hash1:', hash1); console.log('hash2:', hash2); console.log('hash4:', hash4); console.log('hash5:', hash5); return hash1; }
错误响应
{ "responseCode": "110", "responseMessage": "Please provide valid value for pp_SecureHash.", "authenticationStatus": null, "status": null, "gatewayRecommendation": null, "secureHash": "2BBA2766BB4988BF8848A0BFF37F62EFE024CBC544C24B34E851CDB221A48AC2" }
问题解答
1. 版本选择:优先用v2.0
JazzCash目前官方推荐使用v2.0版本,v1.1虽仍兼容,但v2.0提供了更严谨的安全机制(HMAC-SHA256哈希)、更多功能支持,且后续v1.1可能逐步被淘汰。沙箱环境完全支持v2.0,建议切换到该版本,避免后续兼容性问题。
2. Payload字段顺序:不影响哈希验证,但需注意字段格式
JazzCash的哈希计算仅要求按字段名升序排序生成哈希串,请求发送时的字段顺序不影响结果。但你的payload存在两个潜在问题:
pp_CustomerCardNumber是数字类型,JazzCash要求该字段为字符串类型,数字序列化可能导致格式异常;pp_Amount直接转字符串(如100转成"100"),但JazzCash要求金额必须是带两位小数的字符串(如"100.00"),格式不符会导致哈希计算错误。
3. 哈希计算排查方向(核心解决路径)
(1)排除pp_SecureHash字段参与计算
你当前的代码是先构造payload,再添加pp_SecureHash,然后传入generateSecureHash方法。但计算哈希时必须排除pp_SecureHash本身,否则会导致哈希串包含该字段,与网关验证逻辑不符。修改方式:在生成哈希前,先复制payload并移除pp_SecureHash字段,再进行排序计算。
(2)核对Integrity Salt正确性
沙箱和生产环境的Integrity Salt完全不同,必须使用JazzCash官方提供的对应环境的Salt值,不能自定义或混用环境值。
(3)严格遵循对应版本的哈希规则
- v1.1规则:将所有非空必填字段按键名升序拼接为
key=value&key=value格式,在字符串前拼接Integrity Salt,然后执行SHA256哈希,结果转大写; - v2.0规则:使用HMAC-SHA256算法,密钥为Integrity Salt,对排序后的键值串进行哈希。
建议拿JazzCash官方文档中的示例数据,用你的代码计算哈希,对比文档给出的结果,快速定位逻辑错误。
(4)检查请求编码格式
axios默认发送JSON格式请求,但部分支付网关仅支持application/x-www-form-urlencoded编码。尝试将payload转为form-urlencoded格式发送:
import qs from 'qs'; // ... const response = await axios.post(this.baseUrl, qs.stringify(payload), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
(5)验证字段值格式
确认所有字段值符合JazzCash要求:
pp_TxnDateTime和pp_TxnExpiryDateTime必须是YYYYMMDDHHMMSS格式;pp_Amount必须保留两位小数;- 所有字符串字段不能包含多余空格。
内容的提问来源于stack exchange,提问作者Muhammad Fuaad
相关产品推荐
相关产品推荐

