| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | |
| | | extendInfo.put("delay_acct_flag", properties.isDelayAccount() ? "Y" : "N"); |
| | | extendInfo.put("time_expire", command.expiresAt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
| | | request.setExtendInfo(extendInfo); |
| | | log.info("Huifu mini-program payment request: {}", logJson(Map.of( |
| | | "req_date", REQUEST_DATE.format(LocalDateTime.now()), |
| | | "req_seq_id", command.paymentNo(), |
| | | "huifu_id", properties.getMerchantId().trim(), |
| | | "goods_desc", command.goodsDescription(), |
| | | "trans_amt", BigDecimal.valueOf(command.amountInCent(), 2).toPlainString(), |
| | | "trade_type", "T_MINIAPP", |
| | | "system_id", properties.getSystemId().trim(), |
| | | "product_id", properties.getProductId().trim(), |
| | | "extend_info", extendInfo |
| | | ))); |
| | | try { |
| | | return BasePayClient.request(request, false); |
| | | Map<String, Object> response = BasePayClient.request(request, false); |
| | | log.info("Huifu mini-program payment response: {}", logJson(response)); |
| | | return response; |
| | | } catch (Exception exception) { |
| | | // 支付参数包含用户 OpenID 与签名材料,日志仅保留 SDK 错误类型及平台消息。 |
| | | log.warn("Huifu mini-program payment request failed: type={}, message={}", |
| | |
| | | return message.length() > 500 ? message.substring(0, 500) : message; |
| | | } |
| | | |
| | | private String logJson(Object value) { |
| | | try { |
| | | return JSON.toJSONString(sanitizeForLog(value)); |
| | | } catch (Exception ignored) { |
| | | return "{\"log_error\":\"Unable to serialize payment payload\"}"; |
| | | } |
| | | } |
| | | |
| | | private Object sanitizeForLog(Object value) { |
| | | if (value instanceof Map<?, ?> source) { |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | for (Map.Entry<?, ?> entry : source.entrySet()) { |
| | | String key = String.valueOf(entry.getKey()); |
| | | result.put(key, isSensitiveKey(key) ? mask(String.valueOf(entry.getValue())) : sanitizeForLog(entry.getValue())); |
| | | } |
| | | return result; |
| | | } |
| | | if (value instanceof List<?> source) return source.stream().map(this::sanitizeForLog).toList(); |
| | | if (value instanceof String text && (text.startsWith("{") || text.startsWith("["))) { |
| | | try { |
| | | return sanitizeForLog(JSON.parse(text)); |
| | | } catch (Exception ignored) { |
| | | return text; |
| | | } |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | private boolean isSensitiveKey(String key) { |
| | | String normalized = key == null ? "" : key.toLowerCase(); |
| | | return normalized.contains("private") || normalized.contains("secret") || normalized.contains("sign") |
| | | || normalized.contains("openid") || normalized.contains("authorization") || normalized.contains("certificate"); |
| | | } |
| | | |
| | | private String mask(String value) { |
| | | if (value == null || value.isBlank()) return ""; |
| | | if (value.length() <= 8) return "***"; |
| | | return value.substring(0, 4) + "***" + value.substring(value.length() - 4); |
| | | } |
| | | |
| | | private boolean isOutcomeUnknown(Exception exception) { |
| | | String message = safeMessage(exception.getMessage()).toLowerCase(); |
| | | return message.contains("no response") || message.contains("timeout") || message.contains("timed out"); |