sms模拟的路由
This commit is contained in:
@@ -1,36 +1,52 @@
|
|||||||
// Message Gateway 内容发送接口 Mock:POST /ewl/msgw/v1/messages/content/send
|
// Message Gateway 内容发送接口 Mock:POST /ewl/msgw/v1/messages/content/send
|
||||||
// 后端短信已从旧 SMS Hub(/SMSToken + /SMSRequest/Post)切换到该接口,认证复用 EDIP Token。
|
// 后端短信已从旧 SMS Hub(/SMSToken + /SMSRequest/Post)切换到该接口,认证复用 EDIP Token。
|
||||||
// 响应严格按真实网关信封:HTTP 200 + status/errorCode,成功时 smsid 为全小写字段、errorCode 为空字符串。
|
// 响应严格按真实网关信封:HTTP 200 + status/errorCode,成功时 smsid 为全小写字段、errorCode 为空字符串。
|
||||||
const { getForcedErrorCode, getForcedErrorMsg } = require('./smsErrorState')
|
// 支持三类故障注入(见 smsErrorState.js):HTTP 状态码、业务错误码、收件人级失败状态、缺失 smsid。
|
||||||
|
const { getFaultInjection } = require('./smsErrorState')
|
||||||
|
|
||||||
function registerMessageGatewayContentSendRoute({ app }) {
|
function registerMessageGatewayContentSendRoute({ app }) {
|
||||||
app.post('/ewl/msgw/v1/messages/content/send', (req, res) => {
|
app.post('/ewl/msgw/v1/messages/content/send', (req, res) => {
|
||||||
const data = req.body?.data || {}
|
const data = req.body?.data || {}
|
||||||
const recipients = Array.isArray(data.recipients) ? data.recipients : []
|
const recipients = Array.isArray(data.recipients) ? data.recipients : []
|
||||||
|
const fault = getFaultInjection()
|
||||||
|
|
||||||
// 错误注入:优先取运行时开关(/mock-api/sms/content-send-error),回落环境变量。
|
// ① HTTP 层故障:以指定状态码响应,用于验证 4xx 不重试、5xx/429 重试
|
||||||
// 8923 属供应商暂不可用(后端应重试),8907 属号码非法(后端不应重试)
|
if (fault.httpStatus) {
|
||||||
const forcedErrorCode = getForcedErrorCode()
|
return res.status(fault.httpStatus).json({
|
||||||
if (forcedErrorCode) {
|
|
||||||
return res.status(200).json({
|
|
||||||
status: false,
|
status: false,
|
||||||
errorCode: forcedErrorCode,
|
errorCode: fault.errorCode || '',
|
||||||
message: getForcedErrorMsg(),
|
message: fault.errorMsg,
|
||||||
data: null,
|
data: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ② 业务错误码:HTTP 200 + errorCode,用于验证 8901-8910 不重试、8911-8930 重试
|
||||||
|
if (fault.errorCode) {
|
||||||
|
return res.status(200).json({
|
||||||
|
status: false,
|
||||||
|
errorCode: fault.errorCode,
|
||||||
|
message: fault.errorMsg,
|
||||||
|
data: null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ③ 成功响应:可选注入收件人级失败状态(smsStatus=FAILED)与缺失 smsid
|
||||||
|
const recipientStatus = fault.recipientStatus || 'QUEUED'
|
||||||
|
const responseData = {
|
||||||
|
smsStatus: recipients.map((r) => ({
|
||||||
|
recipient: r?.phone || '',
|
||||||
|
status: recipientStatus,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
if (!fault.suppressSmsId) {
|
||||||
|
responseData.smsid = `mock-sms-${Date.now()}`
|
||||||
|
}
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: true,
|
status: true,
|
||||||
errorCode: '',
|
errorCode: '',
|
||||||
message: '',
|
message: '',
|
||||||
data: {
|
data: responseData,
|
||||||
smsid: `mock-sms-${Date.now()}`,
|
|
||||||
smsStatus: recipients.map((r) => ({
|
|
||||||
recipient: r?.phone || '',
|
|
||||||
status: 'QUEUED',
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,76 @@
|
|||||||
// Message Gateway 内容发送 Mock 的运行时错误码开关。
|
// Message Gateway 内容发送 Mock 的运行时故障注入开关。
|
||||||
// 目的:联调时可在进程内切换 errorCode(如 8923 可重试、8907 不可重试),不必反复重启 Mock 进程。
|
// 目的:联调时可在进程内切换故障形态(错误码 / HTTP 状态码 / 收件人级失败 / 缺失 smsid),
|
||||||
// 初值取环境变量 MOCK_SMS_FORCE_ERROR_CODE,之后由 /mock-api/sms/content-send-error 覆盖。
|
// 不必反复重启 Mock 进程。初值取环境变量,之后由 /mock-api/sms/content-send-error 覆盖。
|
||||||
const state = {
|
const state = {
|
||||||
forcedErrorCode: (process.env.MOCK_SMS_FORCE_ERROR_CODE || '').trim(),
|
forcedErrorCode: (process.env.MOCK_SMS_FORCE_ERROR_CODE || '').trim(),
|
||||||
forcedErrorMsg: process.env.MOCK_SMS_FORCE_ERROR_MSG || 'Mock message gateway error',
|
forcedErrorMsg: process.env.MOCK_SMS_FORCE_ERROR_MSG || 'Mock message gateway error',
|
||||||
|
// 非 0 时直接以该 HTTP 状态码响应(用于验证 4xx 不重试、5xx/429 重试)
|
||||||
|
forcedHttpStatus: Number(process.env.MOCK_SMS_FORCE_HTTP_STATUS || 0),
|
||||||
|
// 非空时把每个收件人的 status 替换成该值(用于验证 smsStatus=FAILED 的收件人级失败)
|
||||||
|
forcedRecipientStatus: (process.env.MOCK_SMS_FORCE_RECIPIENT_STATUS || '').trim(),
|
||||||
|
// 为真时成功响应里不返回 smsid(用于验证成功但无网关消息 ID 的审计标注)
|
||||||
|
suppressSmsId: String(process.env.MOCK_SMS_SUPPRESS_SMS_ID || '').toLowerCase() === 'true',
|
||||||
}
|
}
|
||||||
|
|
||||||
function setForcedErrorCode(errorCode, errorMsg) {
|
function normalizeHttpStatus(value) {
|
||||||
state.forcedErrorCode = errorCode == null ? '' : String(errorCode).trim()
|
const status = Number(value || 0)
|
||||||
if (errorMsg != null && String(errorMsg).trim() !== '') {
|
return Number.isInteger(status) && status >= 100 && status <= 599 ? status : 0
|
||||||
state.forcedErrorMsg = String(errorMsg).trim()
|
|
||||||
}
|
|
||||||
return { errorCode: state.forcedErrorCode, errorMsg: state.forcedErrorMsg }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getForcedErrorCode() {
|
/** 覆盖故障注入配置;未提供的字段保持不变,传 null/空串表示清除该项 */
|
||||||
return state.forcedErrorCode
|
function setFaultInjection(overrides = {}) {
|
||||||
|
if (overrides.errorCode !== undefined) {
|
||||||
|
state.forcedErrorCode = overrides.errorCode == null ? '' : String(overrides.errorCode).trim()
|
||||||
|
}
|
||||||
|
if (overrides.errorMsg !== undefined && String(overrides.errorMsg || '').trim() !== '') {
|
||||||
|
state.forcedErrorMsg = String(overrides.errorMsg).trim()
|
||||||
|
}
|
||||||
|
if (overrides.httpStatus !== undefined) {
|
||||||
|
state.forcedHttpStatus = normalizeHttpStatus(overrides.httpStatus)
|
||||||
|
}
|
||||||
|
if (overrides.recipientStatus !== undefined) {
|
||||||
|
state.forcedRecipientStatus =
|
||||||
|
overrides.recipientStatus == null ? '' : String(overrides.recipientStatus).trim()
|
||||||
|
}
|
||||||
|
if (overrides.noSmsId !== undefined) {
|
||||||
|
state.suppressSmsId = Boolean(overrides.noSmsId)
|
||||||
|
}
|
||||||
|
return currentFaultInjection()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getForcedErrorMsg() {
|
function currentFaultInjection() {
|
||||||
return state.forcedErrorMsg
|
return {
|
||||||
|
errorCode: state.forcedErrorCode,
|
||||||
|
errorMsg: state.forcedErrorMsg,
|
||||||
|
httpStatus: state.forcedHttpStatus,
|
||||||
|
recipientStatus: state.forcedRecipientStatus,
|
||||||
|
noSmsId: state.suppressSmsId,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { setForcedErrorCode, getForcedErrorCode, getForcedErrorMsg }
|
/** 清除全部故障注入,回到真实成功响应 */
|
||||||
|
function clearFaultInjection() {
|
||||||
|
state.forcedErrorCode = ''
|
||||||
|
state.forcedErrorMsg = 'Mock message gateway error'
|
||||||
|
state.forcedHttpStatus = 0
|
||||||
|
state.forcedRecipientStatus = ''
|
||||||
|
state.suppressSmsId = false
|
||||||
|
return currentFaultInjection()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFaultInjection() {
|
||||||
|
return {
|
||||||
|
errorCode: state.forcedErrorCode,
|
||||||
|
errorMsg: state.forcedErrorMsg,
|
||||||
|
httpStatus: state.forcedHttpStatus,
|
||||||
|
recipientStatus: state.forcedRecipientStatus,
|
||||||
|
suppressSmsId: state.suppressSmsId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
setFaultInjection,
|
||||||
|
clearFaultInjection,
|
||||||
|
currentFaultInjection,
|
||||||
|
getFaultInjection,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
// Message Gateway 内容发送 Mock 的错误码开关节点(仅联调用)。
|
// Message Gateway 内容发送 Mock 的故障注入开关节点(仅联调用)。
|
||||||
// 用途:进程内切换 errorCode,验后端重试语义(8911-8930 应重试,8901-8910 不应重试),避免反复重启 Mock。
|
// 用途:进程内切换故障形态,验证后端的成功/错误处理与重试语义,避免反复重启 Mock。
|
||||||
const { setForcedErrorCode, getForcedErrorCode, getForcedErrorMsg } = require('../ewl/msgw/smsErrorState')
|
// POST {"errorCode":"8923"} 注入业务错误码(8911-8930 应重试,8901-8910 不应重试)
|
||||||
|
// POST {"httpStatus":401} 注入 HTTP 状态码(4xx 不应重试,5xx/429 应重试)
|
||||||
|
// POST {"recipientStatus":"FAILED"} 注入收件人级失败(整体 200 但 smsStatus=FAILED)
|
||||||
|
// POST {"noSmsId":true} 成功响应中不返回 smsid
|
||||||
|
// DELETE 清除全部注入
|
||||||
|
const {
|
||||||
|
setFaultInjection,
|
||||||
|
clearFaultInjection,
|
||||||
|
currentFaultInjection,
|
||||||
|
} = require('../ewl/msgw/smsErrorState')
|
||||||
|
|
||||||
function registerSmsContentSendErrorOverrideRoute({ app }) {
|
function registerSmsContentSendErrorOverrideRoute({ app }) {
|
||||||
const route = '/mock-api/sms/content-send-error'
|
const route = '/mock-api/sms/content-send-error'
|
||||||
@@ -8,31 +17,28 @@ function registerSmsContentSendErrorOverrideRoute({ app }) {
|
|||||||
app.get(route, (req, res) =>
|
app.get(route, (req, res) =>
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'SMS content send error override retrieved successfully.',
|
message: 'SMS content send fault injection retrieved successfully.',
|
||||||
data: { errorCode: getForcedErrorCode(), errorMsg: getForcedErrorMsg() },
|
data: currentFaultInjection(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
app.post(route, (req, res) => {
|
app.post(route, (req, res) => {
|
||||||
const body = req.body && typeof req.body === 'object' ? req.body : {}
|
const body = req.body && typeof req.body === 'object' ? req.body : {}
|
||||||
const override = setForcedErrorCode(body.errorCode ?? '', body.errorMsg)
|
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'SMS content send error override saved successfully.',
|
message: 'SMS content send fault injection saved successfully.',
|
||||||
data: override,
|
data: setFaultInjection(body),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.delete(route, (req, res) => {
|
app.delete(route, (req, res) =>
|
||||||
const cleared = setForcedErrorCode('', null)
|
res.status(200).json({
|
||||||
|
|
||||||
return res.status(200).json({
|
|
||||||
success: true,
|
success: true,
|
||||||
message: 'SMS content send error override cleared successfully.',
|
message: 'SMS content send fault injection cleared successfully.',
|
||||||
data: cleared,
|
data: clearFaultInjection(),
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = registerSmsContentSendErrorOverrideRoute
|
module.exports = registerSmsContentSendErrorOverrideRoute
|
||||||
|
|||||||
Reference in New Issue
Block a user