You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:54:40