91 lines
2.4 KiB
JavaScript
91 lines
2.4 KiB
JavaScript
const axios = require("axios");
|
|
const crypto = require("crypto");
|
|
const logger = require("../utils/logger");
|
|
const { defaults } = require("./config");
|
|
|
|
const DEFAULT_TIMEOUT = defaults.timeout;
|
|
|
|
function getBaseUrl(overrideUrl) {
|
|
const baseUrl = overrideUrl || defaults.baseUrl;
|
|
if (!baseUrl) {
|
|
throw new Error("短信网关地址未配置: 请设置 CONFIG_SMS_BASE_URL 环境变量");
|
|
}
|
|
return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}`;
|
|
}
|
|
|
|
function encodePayload(payload) {
|
|
const json = JSON.stringify(payload);
|
|
return Buffer.from(json, "utf8").toString("base64");
|
|
}
|
|
|
|
function tryDecodeResponse(data) {
|
|
if (data === null || data === undefined) return data;
|
|
if (typeof data !== "string") return data;
|
|
const trimmed = data.trim();
|
|
if (!trimmed) return "";
|
|
try {
|
|
const decoded = Buffer.from(trimmed, "base64").toString("utf8");
|
|
const normalized = decoded.trim();
|
|
if (!normalized) return decoded;
|
|
if (normalized.startsWith("{") || normalized.startsWith("[")) {
|
|
return JSON.parse(decoded);
|
|
}
|
|
return decoded;
|
|
} catch (err) {
|
|
return data;
|
|
}
|
|
}
|
|
|
|
function buildMac(parts) {
|
|
const raw = parts.join("");
|
|
return crypto.createHash("md5").update(raw, "utf8").digest("hex");
|
|
}
|
|
|
|
async function post(pathname, payload, options = {}) {
|
|
const baseUrl = getBaseUrl(options.baseUrl);
|
|
const url = new URL(pathname, baseUrl).toString();
|
|
const encodedPayload = encodePayload(payload);
|
|
const timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
const headers = {
|
|
"Content-Type": "application/json",
|
|
...(options.headers || {}),
|
|
};
|
|
|
|
const sanitizedPayload = {
|
|
ecName: payload.ecName,
|
|
apId: payload.apId,
|
|
mobiles: payload.mobiles,
|
|
templateId: payload.templateId,
|
|
addSerial: payload.addSerial,
|
|
contentBytes:
|
|
typeof payload.content === "string"
|
|
? Buffer.byteLength(payload.content, "utf8")
|
|
: undefined,
|
|
};
|
|
|
|
logger.info({ scope: "sms-request", url, payload: sanitizedPayload });
|
|
|
|
try {
|
|
const response = await axios.post(url, encodedPayload, {
|
|
timeout,
|
|
headers,
|
|
});
|
|
const decoded = tryDecodeResponse(response.data);
|
|
logger.info({ scope: "sms-response", url, data: decoded });
|
|
return decoded;
|
|
} catch (error) {
|
|
logger.error({
|
|
scope: "sms-request-error",
|
|
url,
|
|
message: error.message,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
post,
|
|
buildMac,
|
|
tryDecodeResponse,
|
|
};
|