如何使用Node.js SMPP发送长短信?超长短信报错求助
解决Node.js SMPP发送长短信时的Buffer越界错误
我来帮你搞定这个长短信发送的问题!你遇到的TypeError: value参数越界错误,本质是因为SMPP协议里的short_message字段有严格长度限制——对于GSM 03.38编码的短信,最多支持160个字符;如果是Unicode(UCS-2)编码,最多只能放140字节(也就是70个双字节字符)。当你的短信内容超过这个限制时,直接塞进short_message就会触发Buffer的长度校验错误。
要解决这个问题,我们需要把长短信拆分成多个"分片",每个分片带上**用户数据头(UDH)**来告诉运营商这是一条拼接短信的一部分,最后由接收端的手机把这些分片重新组合成完整的短信。
解决方案步骤
1. 实现短信拆分与UDH生成工具函数
首先写一个工具函数,用来把长短信拆分成符合要求的分片,并生成对应的UDH:
// 工具函数:拆分长短信并生成带UDH的分片 function splitLongSMS(text, isUnicode = false) { // 根据编码类型设置单分片最大字符数 const maxChars = isUnicode ? 70 : 160; const parts = []; const totalParts = Math.ceil(text.length / maxChars); // 生成0-255之间的唯一参考号,用于标识同一条拼接短信的分片 const referenceNumber = Math.floor(Math.random() * 256); for (let i = 0; i < totalParts; i++) { const start = i * maxChars; const end = start + maxChars; const partText = text.slice(start, end); // 构建UDH格式:05 00 03 [参考号] [总分片数] [当前分片序号] const udh = Buffer.from([ 0x05, // UDH总长度 0x00, // 信息元素标识符:表示拼接短信 0x03, // 信息元素内容长度 referenceNumber, totalParts, i + 1 // 分片序号从1开始计数 ]); parts.push({ udh: udh, text: partText }); } return parts; }
2. 修改sendSMS函数,支持长短信分片发送
接下来修改你原来的sendSMS函数,判断短信长度是否需要拆分,然后分别处理短短信和长短信的情况:
exports.sendSMS = function (session, to, text, sourceAddress, jsonMessageHistoryIds, callback) { console.log('message', text); // 判断是否需要拆分短信(默认用GSM编码,若用Unicode则把第二个参数改为true) const isLongSMS = text.length > 160; let smsParts = []; if (isLongSMS) { smsParts = splitLongSMS(text); } else { smsParts = [{ udh: null, text: text }]; } // 批量提交所有短信分片,用Promise管理异步请求 const submitPromises = smsParts.map((part) => { return new Promise((resolve, reject) => { const submitParams = { source_addr: sourceAddress, dest_address: to, // 有UDH时,设置ESM_CLASS标识并拼接UDH与短信内容 ...(part.udh ? { esm_class: 0x40, // 标记短信包含UDH short_message: Buffer.concat([part.udh, Buffer.from(part.text)]) } : { short_message: part.text }) }; session.submit_multi(submitParams, function (pdu) { console.log('submit_multi: ', pdu.command_status); console.log("PDU", pdu); if (pdu.command_status == 0) { resolve(pdu.message_id); } else { reject(new Error(`提交分片失败,状态码: ${pdu.command_status}`)); } }); }); }); // 等待所有分片提交完成后返回结果 Promise.all(submitPromises) .then((messageIds) => { // 返回所有分片的message_id,也可根据需求只返回第一个 callback(null, messageIds); }) .catch((error) => { callback(error, null); }); };
关键细节说明
- ESM_CLASS设置:发送带UDH的短信时,必须把
esm_class设为0x40,这样运营商才能识别这是拼接短信的一部分。 - 编码适配:如果你的短信包含中文、表情等Unicode字符,需要把
splitLongSMS的isUnicode参数设为true,同时短信内容要用UCS-2编码(比如Buffer.from(text, 'ucs2')),确保分片长度符合140字节的限制。 - 参考号一致性:同一条拼接短信的所有分片必须使用相同的参考号,这样接收端才能正确把分片组合成完整短信。
这样修改后,超过160字符的长短信就会被自动拆分并发送,接收端会自动拼接成完整内容,再也不会触发Buffer越界的错误啦!
内容的提问来源于stack exchange,提问作者Bikash Budhathoki
相关产品推荐
相关产品推荐

