logo

联通短信接口调用全攻略:Java与JS双端实现指南

作者:很酷cat2025.09.17 15:05浏览量:0

简介:本文深入解析Java与JavaScript调用联通短信接口的技术细节,提供从环境配置到异常处理的完整实现方案,助力开发者快速构建短信服务功能。

联通短信接口调用全攻略:Java与JS双端实现指南

一、接口调用前的技术准备

1.1 接口文档解析

联通短信接口采用RESTful架构设计,核心端点包含验证码发送(/sms/send)、状态查询(/sms/query)和余额查询(/account/balance)。接口支持HTTP/HTTPS协议,建议生产环境强制使用HTTPS确保数据传输安全

参数规范方面,必填字段包括:

  • appId:申请的唯一应用标识
  • timestamp:13位时间戳(毫秒级)
  • sign:MD5签名(参数按字典序拼接+密钥)
  • mobile:目标手机号(支持批量发送,逗号分隔)
  • templateId:模板编号(需提前在控制台申请)

1.2 环境搭建要点

Java环境需配置JDK 1.8+和Maven 3.6+,建议使用Hutool工具包简化HTTP请求。JavaScript端推荐Axios库处理异步请求,配合crypto-js进行签名计算。

开发前需完成:

  1. 登录联通云市场申请短信服务
  2. 创建应用获取appId和appKey
  3. 配置IP白名单(测试环境可设为0.0.0.0/0)
  4. 申请短信模板并通过审核

二、Java端实现方案

2.1 核心代码实现

  1. import cn.hutool.http.HttpRequest;
  2. import cn.hutool.crypto.digest.MD5;
  3. import java.util.*;
  4. public class LtsSmsClient {
  5. private String appId;
  6. private String appKey;
  7. public LtsSmsClient(String appId, String appKey) {
  8. this.appId = appId;
  9. this.appKey = appKey;
  10. }
  11. public boolean sendSms(String mobile, String templateId, Map<String, String> params) {
  12. String url = "https://api.106msg.cn/sms/send";
  13. Map<String, Object> paramMap = new HashMap<>();
  14. paramMap.put("appId", appId);
  15. paramMap.put("mobile", mobile);
  16. paramMap.put("templateId", templateId);
  17. paramMap.put("params", params);
  18. paramMap.put("timestamp", System.currentTimeMillis());
  19. // 生成签名
  20. String signStr = appId + mobile + templateId +
  21. params.toString() + System.currentTimeMillis() + appKey;
  22. String sign = MD5.create().digestHex(signStr);
  23. paramMap.put("sign", sign);
  24. try {
  25. String response = HttpRequest.post(url)
  26. .form(paramMap)
  27. .timeout(5000)
  28. .execute()
  29. .body();
  30. // 解析JSON响应(示例省略)
  31. return true;
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. return false;
  35. }
  36. }
  37. }

2.2 高级功能实现

  1. 异步发送优化:使用CompletableFuture实现并发控制

    1. public CompletableFuture<Boolean> asyncSend(String mobile, String templateId) {
    2. return CompletableFuture.supplyAsync(() -> sendSms(mobile, templateId, new HashMap<>()));
    3. }
  2. 重试机制:指数退避算法实现

    1. public boolean sendWithRetry(String mobile, int maxRetry) {
    2. int retry = 0;
    3. while (retry < maxRetry) {
    4. if (sendSms(mobile, "TEMPLATE_001", new HashMap<>())) {
    5. return true;
    6. }
    7. retry++;
    8. try {
    9. Thread.sleep((long) Math.pow(2, retry) * 1000);
    10. } catch (InterruptedException e) {
    11. Thread.currentThread().interrupt();
    12. }
    13. }
    14. return false;
    15. }

三、JavaScript端实现方案

3.1 浏览器端实现

  1. const crypto = require('crypto-js');
  2. class LtsSmsClient {
  3. constructor(appId, appKey) {
  4. this.appId = appId;
  5. this.appKey = appKey;
  6. }
  7. async sendSms(mobile, templateId, params = {}) {
  8. const timestamp = Date.now();
  9. const signStr = `${this.appId}${mobile}${templateId}${JSON.stringify(params)}${timestamp}${this.appKey}`;
  10. const sign = crypto.MD5(signStr).toString();
  11. const response = await axios.post('https://api.106msg.cn/sms/send', {
  12. appId: this.appId,
  13. mobile,
  14. templateId,
  15. params,
  16. timestamp,
  17. sign
  18. }, {
  19. timeout: 5000
  20. });
  21. return response.data;
  22. }
  23. }
  24. // 使用示例
  25. const client = new LtsSmsClient('APP_123', 'SECRET_KEY');
  26. client.sendSms('13800138000', 'TEMPLATE_001')
  27. .then(console.log)
  28. .catch(console.error);

3.2 Node.js服务端优化

  1. 连接池管理:使用axios-retry实现自动重试

    1. const axios = require('axios').create({
    2. maxContentLength: Infinity,
    3. maxBodyLength: Infinity,
    4. retry: 3,
    5. retryDelay: (retryCount) => retryCount * 1000
    6. });
  2. 批量发送实现

    1. async function batchSend(mobiles, templateId) {
    2. const chunks = []; // 分块处理(每批100个号码)
    3. const results = [];
    4. for (let i = 0; i < mobiles.length; i += 100) {
    5. const chunk = mobiles.slice(i, i + 100);
    6. const mobileStr = chunk.join(',');
    7. const response = await client.sendSms(mobileStr, templateId);
    8. results.push(response);
    9. }
    10. return results;
    11. }

四、常见问题解决方案

4.1 签名验证失败

  • 检查参数拼接顺序是否严格按字典序
  • 确认appKey未泄露且未过期
  • 时间戳偏差不超过5分钟

4.2 频率限制处理

接口默认限制:

  • 单IP:50次/秒
  • 单账号:200次/秒
  • 单号码:5次/分钟

解决方案:

  1. // 使用Guava RateLimiter实现限流
  2. private final RateLimiter rateLimiter = RateLimiter.create(10.0); // 每秒10次
  3. public boolean rateLimitedSend(String mobile) {
  4. if (rateLimiter.tryAcquire()) {
  5. return sendSms(mobile, "TEMPLATE_001");
  6. }
  7. return false;
  8. }

4.3 异步回调实现

联通支持回调通知,需在控制台配置回调地址:

  1. @RestController
  2. @RequestMapping("/sms/callback")
  3. public class SmsCallbackController {
  4. @PostMapping
  5. public ResponseEntity<String> handleCallback(
  6. @RequestParam String msgId,
  7. @RequestParam String mobile,
  8. @RequestParam String status,
  9. @RequestParam String reportTime,
  10. @RequestHeader("Sign") String sign) {
  11. // 验证签名(示例省略)
  12. // 处理回调逻辑...
  13. return ResponseEntity.ok("SUCCESS");
  14. }
  15. }

五、最佳实践建议

  1. 安全防护

    • 接口调用IP限制
    • 敏感操作二次验证
    • 定期更换appKey
  2. 性能优化

    • 批量发送减少请求次数
    • 异步处理非实时需求
    • 本地缓存模板信息
  3. 监控体系

    • 发送成功率统计
    • 延迟监控(P99<500ms)
    • 失败自动告警
  4. 合规要求

    • 用户明确授权
    • 退订指令处理
    • 数据存储加密

六、调试与测试技巧

  1. 沙箱环境:使用联通提供的测试账号(前缀170/171号码)
  2. 日志记录
    ```java
    // 使用SLF4J记录关键信息
    private static final Logger logger = LoggerFactory.getLogger(LtsSmsClient.class);

public void logRequest(String url, Map params) {
logger.info(“SMS Request: URL={}, Params={}”, url,
params.entrySet().stream()
.filter(e -> !e.getKey().equals(“sign”))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}

  1. 3. **模拟测试**:
  2. ```javascript
  3. // 使用nock模拟接口响应
  4. const nock = require('nock');
  5. nock('https://api.106msg.cn')
  6. .post('/sms/send')
  7. .reply(200, { code: 0, msgId: 'TEST_123' });

通过以上技术方案的实施,开发者可以构建稳定、高效的联通短信服务系统。实际开发中需根据业务场景选择合适的实现方式,建议先在测试环境完成充分验证后再部署到生产环境。

相关文章推荐

发表评论