简介:企业信使企信通短信平台是一套面向各行业企业集团的短信通信解决方案,适合需要将短信能力嵌入自有业务系统的开发与运维人员,以及关注客户关系管理、市场营销、内部通知等场景的技术团队。平台以稳定可靠、模块化、开放架构和高灵活性为核心,支持定时、批量与触发式发送策略,并提供丰富API接口便于与业务系统对接。压缩包共2447个文件,约26.72MB,以dll动态库、compiled编译文件、aspx页面为主,辅以gif、png、js、css等前端资源,以及mdf、ldf数据库文件、xml与config配置、asmx Web服务接口和少量xls、doc说明文档,整体构成一套可部署的Web短信系统。目前已有364人学习下载。借助该资源,读者可研究短信平台的模块划分、接口调用方式与数据库结构,理解验证码、订单通知、营销推送等业务如何落地,并参考其配置与排错思路,为自建或二次开发企业短信服务提供完整样本。
1. 拆开一个企业短信平台压缩包:从 asmx 接口到批量发送任务,这套源码能跑通什么
拿到一个叫「企业信使企信通短信平台」的压缩包,第一反应不是急着解压看页面,而是先扫一遍文件清单。根目录里躺着SmSWmgwWebService.asmx、SmSWebService.asmx两个 WebService 入口,外加parentdfmmstask.aspx、loopsend.aspx、contacts.aspx、usershowse.aspx、sm.aspx、mnsparenttask.aspx、hisuser.aspx、mmsedit.aspx这一串页面文件。做过短信网关对接的人一眼就能看出来,这是一套典型的 ASP.NET WebForms 架构的企业短信群发系统,前端用 aspx 页面做管理后台,后端用 asmx 暴露短信发送接口,中间靠定时任务和循环发送逻辑撑起批量业务。它解决的核心问题很具体:企业需要把验证码、订单通知、内部公告、营销短信这些消息,通过一个统一平台管起来,而不是每个业务系统各自去对接运营商网关。适合谁用?手里有运营商短信通道资源、需要一套现成管理后台和接口层的中小团队,或者想研究企业短信平台内部任务调度和联系人管理怎么设计的开发者。这套源码不是云服务,它更像一个可私有化部署的短信业务中台骨架,能不能跑起来,取决于你有没有通道账号和 IIS 环境。
2. 两个 asmx 接口的分工:网关对接层和业务发送层怎么切
2.1 SmSWmgwWebService.asmx 与 SmSWebService.asmx 的职责边界
先看这两个 WebService 文件。名字里Wmgw大概率是「网关」的拼音缩写,SmSWmgwWebService应该是对接底层短信网关的适配层,负责把平台内部的发送请求翻译成运营商或网关厂商要求的协议格式。而SmSWebService.asmx更偏向业务层,对外提供发送短信、查询余额、获取状态报告这类业务接口,供企业其他系统调用。
这种分层在短信平台里很常见。网关层要处理的是协议差异——有的网关走 HTTP GET,有的走 WebService,有的走 CMPP 或 SMPP 长连接。业务层则统一参数模型,比如手机号、内容、扩展码、定时时间。两层分开的好处是换网关时只动SmSWmgwWebService,业务系统调用的SmSWebService接口签名不变。
实际部署时,这两个 asmx 通常放在同一个 IIS 站点下,但配置不同的应用程序池,避免网关层阻塞影响业务层响应。如果你只有一套通道,也可以合并,但我不建议,后面排查问题时分层清晰能省很多事。
2.2 接口参数模型与调用示例
假设SmSWebService.asmx暴露了一个SendSms方法,常见参数包括:
| 参数名 | 类型 | 说明 |
|---|---|---|
| mobile | string | 手机号,多个用英文逗号分隔 |
| content | string | 短信内容,需符合运营商长度限制 |
| extCode | string | 扩展码,用于回执匹配 |
| sendTime | string | 定时发送时间,为空则立即发送 |
| priority | int | 优先级,1 最高 |
调用方通常用 C# 的HttpWebRequest或直接添加 Web 引用。下面是一个用 Python 模拟调用的例子,方便你在没有 Visual Studio 的环境下先验证接口是否通:
import requests # 假设 SmSWebService.asmx 的 SendSms 方法接受 JSON 或表单 url = "http://your-server/SmSWebService.asmx/SendSms" payload = { "mobile": "13800138000,13900139000", "content": "您的验证码是 123456,5 分钟内有效。", "extCode": "001", "sendTime": "", "priority": 1 } headers = { "Content-Type": "application/x-www-form-urlencoded" } # 注意:asmx 默认返回 XML,这里只检查 HTTP 状态和原始文本 resp = requests.post(url, data=payload, headers=headers, timeout=10) print(resp.status_code) print(resp.text[:500]) # 截取前 500 字符看返回结构这段代码的关键在于Content-Type。ASP.NET asmx 对表单和 JSON 的支持取决于具体实现,有的方法用[ScriptMethod(ResponseFormat = ResponseFormat.Json)]修饰才能返回 JSON,否则默认是 XML。如果你调的时候返回 500,先看web.config里有没有开system.web.extensions的调试。参数extCode不是所有网关都支持,但留着能对上回执,排查「短信发了但不知道哪条到了」时很有用。
2.3 网关适配层里常见的协议转换逻辑
SmSWmgwWebService.asmx内部一般会做几件事:把手机号列表拼成网关要求的字符串、把内容做 URL 编码或 Base64、计算签名或鉴权头、处理网关返回的错误码并映射成平台内部错误码。常见做法是定义一个GatewayResult类,包含Success、ErrorCode、MessageId三个字段,业务层只认这个结构,不关心网关原始返回。
如果你拿到的源码里这部分是空的或者写死了某家网关的地址,别慌,这是正常的。企业短信平台源码通常只保留适配框架,具体网关参数要自己填。你需要在web.config的appSettings里找GatewayUrl、GatewayAccount、GatewayPassword这类键,没有就自己加,然后在SmSWmgwWebService的构造函数或初始化方法里读。
3. 批量发送任务链:loopsend.aspx 和两个 task 页面怎么串起来
3.1 loopsend.aspx 的循环发送逻辑与性能边界
loopsend.aspx从名字看就是循环发送页。它通常不是给终端用户点的,而是被定时任务或后台线程调用的。典型逻辑是:从数据库取一批待发送记录,逐条或分批调用SmSWebService,更新发送状态,记录回执。
这里有个性能边界要注意。如果loopsend.aspx里用的是foreach逐条调用 WebService,每条都建立一次 HTTP 连接,那发送 1000 条短信可能要几分钟甚至超时。常见优化是改成批量接口,一次传 100 个手机号,或者用异步并行。但并行度不能太高,运营商网关一般有限流,开 50 个线程同时发,大概率被封。
我一般会看loopsend.aspx里有没有Thread.Sleep或Task.Delay。如果有,说明作者考虑了限流,但硬编码的延迟值不一定适合你的通道。你需要根据网关的 QPS 限制调整,比如网关允许 100 条/秒,那延迟设 10ms 左右,但实际还要留余量。
3.2 parentdfmmstask.aspx 与 mnsparenttask.aspx 的任务调度差异
这两个 task 页面名字里都有parent和task,dfmms和mns可能是不同业务线的缩写。dfmms可能偏向「定时群发任务」,mns可能偏向「彩信或多媒体消息任务」。它们通常实现IHttpHandler或继承Page但只执行后台逻辑,由 Windows 计划任务或Global.asax里的定时器触发。
你需要确认它们的触发方式。如果是计划任务,看任务计划程序里有没有对应项;如果是Global.asax里的Timer,看Application_Start里有没有注册。常见坑是:IIS 应用程序池回收后,Global.asax里的定时器会停,直到下一个请求进来才重启。所以生产环境更稳的做法是用 Windows 服务或独立计划任务去调loopsend.aspx,而不是依赖 Web 进程内的定时器。
3.3 任务状态回写与 hisuser.aspx 的历史记录查询
hisuser.aspx是历史记录查询页,通常按用户、时间、发送状态筛选。它和 task 页面的关系是:task 负责发,hisuser 负责查。发送状态一般有「待发送」「发送中」「发送成功」「发送失败」「未知」几种。未知状态最麻烦,通常是网关返回了超时或无法识别的错误码。
排查时先看hisuser.aspx的查询 SQL 有没有走索引。如果表数据量大,按手机号或时间查很慢,需要加索引。另外注意状态回写是否及时,有的实现是发送后立即写「发送中」,等回执到了再更新,如果回执接口没配好,状态会一直卡在「发送中」。
4. 联系人管理与内容编辑:contacts.aspx、sm.aspx、mmsedit.aspx 的实操细节
4.1 contacts.aspx 的联系人导入与去重策略
contacts.aspx是联系人管理页。企业短信平台的联系人通常按分组管理,支持 Excel 导入。导入时最容易翻车的是手机号格式:有的带 +86,有的带空格,有的 Excel 把手机号存成科学计数法。常见做法是在导入前用正则清洗,统一成 11 位数字。
去重策略要看业务。营销短信一般允许同一号码在不同分组里存在,但发送时要按号码去重,避免重复打扰。内部通知可能允许重复。你需要在contacts.aspx的导入逻辑里找Distinct或GROUP BY,没有就自己加。
4.2 sm.aspx 的短信内容编辑与长度计算
sm.aspx是短信编辑页。短信长度计算不是简单的字符数:纯英文 160 字符一条,中文 70 字符一条,超过就拆分。如果内容里有 URL 或特殊符号,还要考虑编码后的长度。常见坑是前端显示「剩余 10 字」,实际发送时因为签名和扩展码占位,被拆成两条。
你可以在sm.aspx里加一个实时计算逻辑,用 JavaScript 按中文 70、英文 160 估算,并在提交前再校验一次。签名一般由网关自动加,但有的平台要求内容里自己带,看web.config里的SmsSignature配置。
4.3 mmsedit.aspx 的彩信编辑与资源路径
mmsedit.aspx是彩信编辑页。彩信和短信不同,它要上传图片、音频等资源,并生成 SMIL 文件。常见问题是资源路径用了相对路径,部署到 IIS 后找不到文件。你需要确认上传目录的权限,IIS 应用程序池账户要有写权限。
另外彩信大小有限制,一般不超过 300KB。编辑页应该在前端校验,但后端也要校验,防止绕过。如果源码里没有校验,自己加一个FileUpload的大小检查。
5. 避坑与排查:部署这套源码时最容易卡住的五个地方
5.1 现象:asmx 页面能打开但调用返回 500
原因:web.config里缺少system.web.extensions配置,或者ScriptModule没注册。解决:在web.config的system.web下加<httpModules>和<httpHandlers>,具体参考 ASP.NET AJAX 的标准配置。如果还不行,看 IIS 的「处理程序映射」里.asmx是否指向aspnet_isapi.dll。
5.2 现象:loopsend.aspx 执行到一半超时
原因:IIS 默认脚本超时 90 秒,批量发送超过就断。解决:在web.config的httpRuntime里把executionTimeout调大,比如 600 秒。但更好的做法是把批量任务拆成小批次,每批 100 条,用计划任务多次调用。
5.3 现象:联系人导入后手机号变成科学计数法
原因:Excel 默认把长数字转成科学计数法,导入时没做格式转换。解决:在导入前把 Excel 列格式设为文本,或者在代码里用decimal或string读取,不要用double。如果已经导入错了,用 SQL 更新把1.38E+10这种还原成 11 位。
5.4 现象:短信发送成功但 hisuser.aspx 里状态一直是「发送中」
原因:回执接口没配,或者回执处理页面没被调用。解决:检查SmSWmgwWebService里有没有ReceiveReport方法,以及网关是否配置了回执推送地址。如果是拉取模式,看parentdfmmstask.aspx里有没有定时拉回执的逻辑。
5.5 现象:部署后页面样式错乱或按钮无响应
原因:静态资源路径用了绝对路径,或者ScriptResource.axd被 IIS 拦截。解决:把路径改成相对路径,或者在web.config里放行axd扩展名。另外检查浏览器控制台有没有 404,常见的是WebResource.axd没加载。
6. 进阶技巧:用日志和状态机把发送成功率从 85% 拉到 98%
这套源码默认的日志可能只记了「发送成功/失败」,没有记录网关原始返回和耗时。我一般会加一张SmsSendLog表,字段包括Mobile、Content、GatewayUrl、RequestTime、ResponseTime、GatewayCode、PlatformStatus。每次调用网关前后各写一条,这样排查时能精确知道是网络慢还是网关拒绝。
状态机也要明确。我习惯用五个状态:Pending、Sending、Sent、Delivered、Failed。Sent表示网关已接收,Delivered表示回执确认到达。很多平台把Sent当成功,实际用户可能没收到。加上回执匹配后,成功率统计才准。
下面是一个简单的状态更新 SQL,放在loopsend.aspx的发送逻辑里:
-- 发送前标记为 Sending UPDATE SmsTask SET Status = 'Sending', SendTime = GETDATE() WHERE Id = @TaskId AND Status = 'Pending'; -- 网关返回成功后标记为 Sent UPDATE SmsTask SET Status = 'Sent', GatewayMsgId = @MsgId WHERE Id = @TaskId AND Status = 'Sending'; -- 回执到达后标记为 Delivered 或 Failed UPDATE SmsTask SET Status = @FinalStatus, ReportTime = GETDATE() WHERE GatewayMsgId = @MsgId AND Status = 'Sent';注意WHERE条件里的状态判断,防止并发重复更新。如果@@ROWCOUNT为 0,说明状态已经被其他线程改了,需要记录异常。
还有一个技巧是给loopsend.aspx加一个「发送速率」配置,从web.config读,单位是「条/秒」。代码里用Stopwatch控制,每发一条检查是否超过速率,超了就Thread.Sleep。这样换网关时只改配置,不用改代码。
从那以后我每次部署这类短信平台,都强制先跑一遍「单条发送 → 查历史 → 对回执」的闭环,再开批量任务。希望帮到你。
本文还有配套的精品资源,点击获取