- 在使用类似强退的机制情况下能调起Unload吗?
如题,我写了一个当用户卸载页面时,调起出场函数的代码,如下所示。、 onUnload() { if (this.data.debugMode) { // 维修接口 console.log("【DebugMode=true】",'onUnload'); } if (this.data.logTimer) { clearInterval(this.data.logTimer); this.data.logTimer = null; } this.LeaveUser(); // 用户出场 }, 在实际使用(实机调试-电脑)的时候,我总会发现大部分直接关闭调试页面的场景下,用户出场的内容未被调起。 请问这是正常的吗?如果是正常的,那有办法避免吗(在不考虑修正用户行为习惯的情况下)?
04-03 - 【已解决】代码没错,但仍然弹出”签名错误,请检查后再试“?
简述问题:前端后端都无问题,通过自带的例子尝试生成的签名值与程序生成的签名值一致。检查数据格式和内容没有任何非法字符,但仍然弹出签名错误的401回复。 后端JS: // PerpayController.java @RestController @RequestMapping("/api/perpay") public class PerpayController { @Autowired private PayService payService; private static final Logger log = LoggerFactory.getLogger(PayService.class); // POST @PostMapping public String handlePostRequest(@RequestBody PayRequest payRequest) throws Exception { log.info("Received POST request with body: " + payRequest); return payService.generateAuthorizationHeader("POST", "/v3/pay/transactions/jsapi", payRequest); } } // PayService.java @Service public class PayService { private static final Logger log = LoggerFactory.getLogger(PayService.class); // 生成Authorization头 public String generateAuthorizationHeader(String method, String url, PayRequest payRequest) throws Exception { log.info("开始生成Authorization头, method: {}, url: {}", method, url); String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr = SignatureUtil.generateRandomString(); log.info("生成的时间戳: {}", timestamp); log.info("生成的随机字符串: {}", nonceStr); String requestBody = (payRequest != null) ? payRequest.toString() : ""; // GET为空 log.info("请求体: {}", requestBody); String signString = SignatureUtil.createSignString(method, url, timestamp, nonceStr, requestBody); String signature = SignatureUtil.signWithRSA(signString); String authorizationHeader = SignatureUtil.createAuthorizationHeader(signature, timestamp, nonceStr); return authorizationHeader; } } // SignatureUtil.java public class SignatureUtil { private static final Logger log = LoggerFactory.getLogger(SignatureUtil.class); // 随机字符串 public static String generateRandomString() { String randomString = UUID.randomUUID().toString().replace("-", "").toUpperCase(); return randomString; } // 构造签名串 public static String createSignString(String method, String url, String timestamp, String nonceStr, String requestBody) { String signString = method + "\n" + url + "\n" + timestamp + "\n" + nonceStr + "\n" + requestBody + "\n"; return signString; } // RSA计算签名 public static String signWithRSA(String data) throws Exception { log.info("RSA私钥计算签名, 计算数据: {}", data); PrivateKey privateKey = loadPrivateKey("/home/resource/16800000_20250120_cert/apiclient_key.pem"); Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(data.getBytes()); byte[] signedBytes = signature.sign(); String base64Signature = Base64.getEncoder().encodeToString(signedBytes); log.info("计算的签名: {}", base64Signature); Files.write(Paths.get("/tmp/java_input.txt"), data.getBytes(StandardCharsets.UTF_8)); return base64Signature; } private static PrivateKey loadPrivateKey(String privateKeyPath) throws Exception { log.info("加载私钥, 路径: {}", privateKeyPath); Path path = Paths.get(privateKeyPath); byte[] keyBytes = Files.readAllBytes(path); String privateKeyPEM = new String(keyBytes) .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s", ""); byte[] decoded = Base64.getDecoder().decode(privateKeyPEM); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decoded)); log.info("私钥加载成功"); return privateKey; } // 生成Authorization头 public static String createAuthorizationHeader(String signature, String timestamp, String nonceStr) { String mchid = "168000000"; String serialNo = "4850000000000000000000000000000000000"; // cert.pem序列号 String authorizationHeader = "WECHATPAY2-SHA256-RSA2048 " + "mchid=\"" + mchid + "\"," + // 注意这里没有空格 "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\"" + serialNo + "\""; log.info("Authorization:{}", authorizationHeader); return authorizationHeader; } } 前端JS(我觉得应该没啥问题): Page({ data: { formData: {} }, onLoad: function(options) { if (options.product) { const product = JSON.parse(options.product); this.setData({ formData: { description: `NO.${product.id}-${product.name}`, out_trade_no: `${new Date().getFullYear()}${('0' + (new Date().getMonth() + 1)).slice(-2)}${('0' + new Date().getDate()).slice(-2)}${('0' + new Date().getHours()).slice(-2)}${('0' + new Date().getMinutes()).slice(-2)}${('0' + new Date().getSeconds()).slice(-2)}${('000000' + wx.getStorageSync('userid')).slice(-6)}${('000000' + product.id).slice(-6)}000000`, // 由于代码只能显示UTC时间,所以原本+5分钟改成+485分钟,懒了之后再想办法修,先这么用 time_expire: new Date(Date.now() + 490 * 60 * 1000).toISOString().replace('Z', '+08:00').split('.')[0] + '+08:00', attach: `${product.id}-${product.name}-${wx.getStorageSync('userid')}`, notify_url: 'https://www.qqsh.com.cn:8443/api/notify', amount_total: product.price, amount_currency: 'CNY', payer_openid: wx.getStorageSync('openid'), } }); } }, createWeChatPayOrder: function (e) { const formData = e.detail.value; const data = { appid: 'wx********', mchid: '16800000000', description: formData.description, out_trade_no: formData.out_trade_no, time_expire: formData.time_expire, attach: formData.attach, notify_url: formData.notify_url, amount: { total: parseInt(formData.amount_total, 10) * 100, // 订单总金额(分) currency: formData.amount_currency }, payer: { openid: formData.payer_openid }, }; console.log('data', data); wx.request({ url: 'https://www.qqsh.com.cn:8443/api/perpay', // 获取授权信息的API method: 'POST', header: { 'Content-Type': 'application/json', 'Authorization': `${wx.getStorageSync('userToken')}` // 替换为实际的 token }, data: JSON.stringify(data), success: (res) => { console.log('data:', JSON.stringify(data)); console.log('Response from perpay API:', res.data); const authorizationHeader = `${res.data}`; console.log('Authorization:', authorizationHeader); console.log('Form Data:', data); // 微信支付请求 wx.request({ url: 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', // 设置请求URL method: 'POST', header: { 'Authorization': authorizationHeader, // 使用从 api/perpay 中获得的 Authorization 头 'Accept': 'application/json', // 设置接受的数据类型 'Content-Type': 'application/json' // 设置请求的数据类型 }, data: JSON.stringify(data), // 设置请求数据 success: function (res) { // console.log('Header sent in the request:', { // 'Authorization': authorizationHeader, // 使用从 api/perpay 中获得的 Authorization 头 // 'Accept': 'application/json', // 设置接受的数据类型 // 'Content-Type': 'application/json' // 设置请求的数据类型 // }); const paymentData = res.data; // 获取返回的支付数据 console.log('paymentData:', paymentData); // 打印支付数据 // 获取timeStamp const timeStamp = `${Math.floor(new Date().getTime() / 1000)}`; console.log('时间戳:', timeStamp); }, fail: function(res) { console.error('支付订单创建失败', res); } }); }, fail: (err) => { console.error('请求perpay接口失败', err); // 打印请求perpay失败信息 } }); } }); 前端返回(片段): paynew.js:300 data {appid: "wx****************", mchid: "1680000000", description: "NO.172-啤酒-扬子集团黑松露听装", out_trade_no: "20250205064658000001000172000000", time_expire: "2025-02-05T06:56:58+08:00", …}amount: {total: 100, currency: "CNY"}appid: "wx****************"attach: "172-啤酒-扬子集团黑松露听装-1"description: "NO.172-啤酒-扬子集团黑松露听装"mchid: "1680000000"notify_url: "https://www.qqsh.com.cn:8443/api/notify"out_trade_no: "20250205064658000001000172000000"payer: {openid: "oionx61-*******************"}time_expire: "2025-02-05T06:56:58+08:00"__proto__: Object paynew.js:312 data: {"appid":"wx****************","mchid":"1680000000","description":"NO.172-啤酒-扬子集团黑松露听装","out_trade_no":"20250205064658000001000172000000","time_expire":"2025-02-05T06:56:58+08:00","attach":"172-啤酒-扬子集团黑松露听装-1","notify_url":"https://www.qqsh.com.cn:8443/api/notify","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oionx61-*******************"}} paynew.js:313 Response from perpay API: WECHATPAY2-SHA256-RSA2048 mchid="1680000000",nonce_str="464516C9AFB848DC80B21063BD6DA53A",signature="pfC21Yj3eNOTFvw6eys0PsxCS5egYvlXcRRPiKieUTTHUOBFYAwrmmem6TB/AjuBvemjI3xTgGjy+PZkcvk/hJ6703zC+Kv9TntAsbPDcTGWZH9tSMWxu9x0cREBC/q3ZI5GwzG1R5Zw0Hr1VHLzFmqjGyRju2SQvQIPhBKW9mc9OaDqzG2vdwpWWvV66lbhOeqpcd+UzvTq3h6GIxhCpo5nZ+sIMYMb1S/1eRkqQUHhq4/VX9JM/xdFXpqi2eXRsmjQX+rHYudx3q8vrbzgHLfYsCwC+UGdWXc6pwalUz4428gN+2HKSluDF73KYi0/ScDmCTrj/tJ0dos+zQDPZw==",timestamp="1738709223",serial_no="485773B800000000000000000" paynew.js:322 Generated Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1680000000",nonce_str="464516C9AFB848DC80B21063BD6DA53A",signature="pfC21Yj3eNOTFvw6eys0PsxCS5egYvlXcRRPiKieUTTHUOBFYAwrmmem6TB/AjuBvemjI3xTgGjy+PZkcvk/hJ6703zC+Kv9TntAsbPDcTGWZH9tSMWxu9x0cREBC/q3ZI5GwzG1R5Zw0Hr1VHLzFmqjGyRju2SQvQIPhBKW9mc9OaDqzG2vdwpWWvV66lbhOeqpcd+UzvTq3h6GIxhCpo5nZ+sIMYMb1S/1eRkqQUHhq4/VX9JM/xdFXpqi2eXRsmjQX+rHYudx3q8vrbzgHLfYsCwC+UGdWXc6pwalUz4428gN+2HKSluDF73KYi0/ScDmCTrj/tJ0dos+zQDPZw==",timestamp="1738709223",serial_no="485773B800000000000000000" paynew.js:324 Form Data: {amount: {total: 100, currency: "CNY"},appid: "wx****************",attach: "172-啤酒-扬子集团黑松露听装-1",description: "NO.172-啤酒-扬子集团黑松露听装",mchid: "1680000000",notify_url: "https://www.qqsh.com.cn:8443/api/notify",out_trade_no: "20250205064658000001000172000000",payer: {openid: "oionx61-*******************"},time_expire: "2025-02-05T06:56:58+08:00",__proto__: Object} paynew.js:347 支付数据: {code: "SIGN_ERROR", detail: {…}, message: "签名错误,请检查后再试"} paynew.js:351 生成的时间戳: 1738709219 后端返回(片段): com.miniprogram.service.PayService : Received POST request with body: {"appid":"wx****************","mchid":"1680000000","description":"NO.172-啤酒-扬子集团黑松露听装","out_trade_no":"20250205064658000001000172000000","notify_url":"https://www.qqsh.com.cn:8443/api/notify","time_expire":"2025-02-05T06:56:58+08:00","attach":"172-啤酒-扬子集团黑松露听装-1","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oionx61-*******************"}} com.miniprogram.service.PayService : 开始生成Authorization头, method: POST, url: /v3/pay/transactions/jsapi com.miniprogram.service.PayService : 生成的时间戳: 1738709223 com.miniprogram.service.PayService : 生成的随机字符串: 464516C9AFB848DC80B21063BD6DA53A com.miniprogram.service.PayService : 请求体: {"appid":"wx****************","mchid":"1680000000","description":"NO.172-啤酒-扬子集团黑松露听装","out_trade_no":"20250205064658000001000172000000","notify_url":"https://www.qqsh.com.cn:8443/api/notify","time_expire":"2025-02-05T06:56:58+08:00","attach":"172-啤酒-扬子集团黑松露听装-1","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oionx61-*******************"}} com.miniprogram.util.SignatureUtil : 开始使用RSA私钥计算签名, 计算数据: POST /v3/pay/transactions/jsapi 1738709223 464516C9AFB848DC80B21063BD6DA53A {"appid":"wx****************","mchid":"1680000000","description":"NO.172-啤酒-扬子集团黑松露听装","out_trade_no":"20250205064658000001000172000000","notify_url":"https://www.qqsh.com.cn:8443/api/notify","time_expire":"2025-02-05T06:56:58+08:00","attach":"172-啤酒-扬子集团黑松露听装-1","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oionx61-*******************"}} com.miniprogram.util.SignatureUtil : 加载私钥, 路径: /home/resource/1680000000_20250120_cert/apiclient_key.pem com.miniprogram.util.SignatureUtil : 私钥加载成功 com.miniprogram.util.SignatureUtil : 计算的签名: pfC21Yj3eNOTFvw6eys0PsxCS5egYvlXcRRPiKieUTTHUOBFYAwrmmem6TB/AjuBvemjI3xTgGjy+PZkcvk/hJ6703zC+Kv9TntAsbPDcTGWZH9tSMWxu9x0cREBC/q3ZI5GwzG1R5Zw0Hr1VHLzFmqjGyRju2SQvQIPhBKW9mc9OaDqzG2vdwpWWvV66lbhOeqpcd+UzvTq3h6GIxhCpo5nZ+sIMYMb1S/1eRkqQUHhq4/VX9JM/xdFXpqi2eXRsmjQX+rHYudx3q8vrbzgHLfYsCwC+UGdWXc6pwalUz4428gN+2HKSluDF73KYi0/ScDmCTrj/tJ0dos+zQDPZw== com.miniprogram.util.SignatureUtil : Authorization:WECHATPAY2-SHA256-RSA2048 mchid="1680000000",nonce_str="464516C9AFB848DC80B21063BD6DA53A",signature="pfC21Yj3eNOTFvw6eys0PsxCS5egYvlXcRRPiKieUTTHUOBFYAwrmmem6TB/AjuBvemjI3xTgGjy+PZkcvk/hJ6703zC+Kv9TntAsbPDcTGWZH9tSMWxu9x0cREBC/q3ZI5GwzG1R5Zw0Hr1VHLzFmqjGyRju2SQvQIPhBKW9mc9OaDqzG2vdwpWWvV66lbhOeqpcd+UzvTq3h6GIxhCpo5nZ+sIMYMb1S/1eRkqQUHhq4/VX9JM/xdFXpqi2eXRsmjQX+rHYudx3q8vrbzgHLfYsCwC+UGdWXc6pwalUz4428gN+2HKSluDF73KYi0/ScDmCTrj/tJ0dos+zQDPZw==",timestamp="1738709223",serial_no="485773B800000000000000000" 前端打包数据没错,传入后端没错,极端签名没错,传回签名没错,发送签名没错,我实在是不知道哪里出了问题了,这问题我查了好几天都没查到,特来问各位大佬有没有懂得帮我望一下看一眼我哪里出问题了,谢谢各位! =========================================== 2025-02-07 08:30 更新 在多微信公众号的情况下,一定要检查【微信开发者工具】的AppID。简单复制再导入一份工程文件然后再赋值新的AppID是没有用的。 一定一定一定要检查AppID。
02-05