| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- const axios = require('axios')
- const config = require('../config.json')
- function getPaymentConfig() {
- return config.pay || {}
- }
- function normalizePayBaseUrl(url) {
- return String(url || '').trim().replace(/\/+$/, '')
- }
- function buildPaymentApiUrl(act, params = {}) {
- const paymentConfig = getPaymentConfig()
- const baseUrl = normalizePayBaseUrl(paymentConfig.url)
- if (!baseUrl) {
- throw new Error('支付配置错误')
- }
- const url = new URL(`${baseUrl}/api.php`)
- url.searchParams.set('act', act)
- for (const [key, value] of Object.entries(params)) {
- if (value === undefined || value === null || value === '') continue
- url.searchParams.set(key, String(value))
- }
- return url.toString()
- }
- function parsePaymentResponseBody(data) {
- if (data && typeof data === 'object') return data
- if (typeof data !== 'string') return null
- const text = data.trim()
- if (!text) return null
- try {
- return JSON.parse(text)
- } catch (_) {
- return null
- }
- }
- function getAxiosPaymentOptions(extra = {}) {
- return {
- timeout: 15000,
- maxRedirects: 5,
- proxy: false,
- validateStatus: (status) => status >= 200 && status < 500,
- ...extra
- }
- }
- function formatPaymentHttpError(error, fallbackMessage) {
- if (error?.code === 'ECONNABORTED') {
- return '支付平台响应超时,请稍后重试'
- }
- if (error?.code === 'ERR_FR_TOO_MANY_REDIRECTS') {
- return '支付平台重定向异常,请检查 pay.url 配置或关闭系统代理后重试'
- }
- const status = Number(error?.response?.status || 0)
- const parsed = parsePaymentResponseBody(error?.response?.data)
- if (parsed?.msg) return String(parsed.msg)
- if (status === 503) return '支付平台暂时不可用,请稍后重试'
- if (status >= 500) return `支付平台异常(${status}),请稍后重试`
- return fallbackMessage || error?.message || '支付平台请求失败'
- }
- async function queryPaymentOrder(orderId, logger) {
- const paymentConfig = getPaymentConfig()
- if (!paymentConfig.pid || !paymentConfig.url || !paymentConfig.key) {
- throw new Error('支付配置错误')
- }
- const queryUrl = buildPaymentApiUrl('order', {
- pid: paymentConfig.pid,
- key: paymentConfig.key,
- out_trade_no: orderId
- })
- let response
- try {
- response = await axios.get(queryUrl, getAxiosPaymentOptions())
- } catch (error) {
- const message = formatPaymentHttpError(error, '查询支付状态失败')
- logger?.warn?.(`查询支付状态失败,订单号:${orderId},URL:${queryUrl},原因:${message}`)
- throw new Error(message)
- }
- const result = parsePaymentResponseBody(response.data)
- if (!result) {
- logger?.warn?.(`支付平台返回非 JSON,订单号:${orderId},HTTP ${response.status}`)
- throw new Error('支付平台响应异常')
- }
- return result
- }
- function formatPaymentRefundError(response, fallbackMessage) {
- return formatPaymentHttpError({ response }, fallbackMessage || '支付平台退款失败')
- }
- async function requestPaymentRefund({ orderId, tradeNo, money, logger }) {
- const paymentConfig = getPaymentConfig()
- if (!paymentConfig.url || !paymentConfig.pid || !paymentConfig.key) {
- throw new Error('支付配置错误')
- }
- const refundUrl = buildPaymentApiUrl('refund')
- const params = new URLSearchParams()
- params.append('pid', String(paymentConfig.pid))
- params.append('key', paymentConfig.key)
- if (tradeNo) {
- params.append('trade_no', tradeNo)
- } else {
- params.append('out_trade_no', orderId)
- }
- params.append('money', String(money))
- let response
- try {
- response = await axios.post(
- refundUrl,
- params.toString(),
- getAxiosPaymentOptions({
- timeout: 30000,
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
- validateStatus: () => true
- })
- )
- } catch (error) {
- logger?.error?.(`易支付退款请求失败 订单号:${orderId}:${error.stack || error}`)
- throw new Error(formatPaymentHttpError(error, '无法连接支付平台,请稍后重试'))
- }
- const result = parsePaymentResponseBody(response.data)
- logger?.info?.(`易支付退款响应 订单号:${orderId},HTTP ${response.status},结果:${JSON.stringify(result ?? response.data)}`)
- if (response.status >= 400) {
- throw new Error(formatPaymentRefundError(response, '支付平台退款失败'))
- }
- if (!result || Number(result.code) !== 1) {
- throw new Error(result?.msg || '支付平台退款失败')
- }
- return result
- }
- module.exports = {
- normalizePayBaseUrl,
- buildPaymentApiUrl,
- getAxiosPaymentOptions,
- formatPaymentHttpError,
- formatPaymentRefundError,
- parsePaymentResponseBody,
- queryPaymentOrder,
- requestPaymentRefund
- }
|