当你需要在应用中集成短信功能时,最耗时的往往不是业务逻辑设计,而是花大量时间翻文档、调试请求格式、处理各种语言环境的HTTP客户端差异。虽然不同短信服务商的API认证方式和端点在细节上有所不同,但绝大多数现代短信API都遵循统一的RESTful设计规范——使用Bearer Token认证、接收JSON格式的请求体、返回结构化的JSON响应。
本文汇总了五种主流编程语言的短信发送代码示例,所有代码均使用标准的HTTP客户端库实现,不依赖特定服务商的SDK。这意味着无论你使用的是蓝蓝通信、Msg91、Twilio还是其他服务商,只需替换API端点URL和认证信息,代码即可直接使用。
Python生态中最常用的HTTP客户端是`requests`库,它以简洁的API设计而著称。以下代码展示了如何通过Bearer Token认证发送一条交易短信:
```python
import requests
import os
从环境变量读取API密钥(安全最佳实践,切勿在代码中硬编码)
API_KEY = os.getenv("SMS_API_KEY")
API_URL = "https://www.lanlansms.com/v1/sms/send"
def send_sms(phone_number: str, message: str, sender_id: str = "SPREDG") -> dict:
"""
发送单条短信
Args:
phone_number: 接收方手机号,格式必须包含国家代码(印度为+91)
message: 短信内容
sender_id: 发送方ID(需在DLT系统备案)
Returns:
API响应的JSON数据
"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
payload = {
"to": phone_number,
"sender_id": sender_id,
"message": message,
"type": "transactional" 交易短信通道,适合OTP和订单通知
}
try:
response = requests.post(API_URL, json=payload, headers=headers, timeout=10)
response.raise_for_status() 自动处理4xx/5xx状态码
result = response.json()
print(f"✅ 发送成功!Message ID: {result.get('message_id')}")
return result
except requests.exceptions.RequestException as e:
print(f"❌ 发送失败: {e}")
return {"error": str(e)}
调用示例
if __name__ == "__main__":
send_sms("+919876543210", "Your OTP is 654321")
```
> **最佳实践**:生产环境中务必使用`os.getenv()`从环境变量读取API密钥,切勿将密钥硬编码在代码中。对于需要批量发送的场景,建议复用`requests.Session()`以启用连接池,减少每次请求的TCP握手开销。
批量发送
对于需要同时向多个号码发送相同内容的企业,批量发送可以大幅提升效率。单次API调用最多可支持10,000个收件人,显著减少网络往返次数:
```python
def send_bulk_sms(phone_numbers: list, message: str, sender_id: str = "SPREDG") -> dict:
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
大多数服务商的批量接口接受recipients数组
payload = {
"recipients": phone_numbers,
"sender_id": sender_id,
"message": message,
"type": "transactional"
}
response = requests.post(API_URL, json=payload, headers=headers, timeout=30)
return response.json()
```
Java开发者通常使用OkHttp或Apache HttpClient来处理HTTP请求。OkHttp因其现代化的API设计和内置的连接池管理而受到广泛欢迎。以下使用OkHttp实现短信发送:
```java
import okhttp3.*;
import java.io.IOException;
public class SMSClient {
private static final String API_URL = "https://www.lanlansms.com/v1/sms/send";
private static final String API_KEY = System.getenv("SMS_API_KEY");
private static final String SENDER_ID = "SPREDG";
// OkHttpClient应设计为单例,复用连接池
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
public static JsonObject sendSms(String phoneNumber, String message) throws IOException {
// 构建JSON请求体
JsonObject payload = new JsonObject();
payload.addProperty("to", phoneNumber);
payload.addProperty("sender_id", SENDER_ID);
payload.addProperty("message", message);
payload.addProperty("type", "transactional");
// 构建HTTP请求
RequestBody body = RequestBody.create(
MediaType.parse("application/json"),
payload.toString()
);
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer " + API_KEY)
.build();
try (Response response = client.newCall(request).execute()) {
String responseBody = response.body().string();
System.out.println("Response: " + responseBody);
if (response.isSuccessful()) {
System.out.println("✅ 发送成功");
} else {
System.err.println("❌ 发送失败,HTTP状态码: " + response.code());
}
return JsonParser.parseString(responseBody).getAsJsonObject();
}
}
public static void main(String[] args) {
try {
sendSms("+919876543210", "Your OTP is 654321");
} catch (IOException e) {
System.err.println("发送异常: " + e.getMessage());
}
}
}
```
> **注意事项**:生产环境中应将`OkHttpClient`设计为单例模式,因为每个实例都维护自己的连接池和线程池。频繁创建新实例会导致资源浪费和性能下降。
使用Apache HttpClient的备选方案
如果项目已经依赖Apache HttpClient,也可以使用以下实现:
```java
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class SMSClientApache {
public void sendSms(String mobile, String message) throws Exception {
String jsonBody = String.format(
"{\"to\":\"%s\",\"sender_id\":\"%s\",\"message\":\"%s\",\"type\":\"transactional\"}",
mobile, "SPREDG", message
);
HttpPost httpPost = new HttpPost("https://www.lanlansms.com/v1/sms/send");
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("Authorization", "Bearer " + System.getenv("SMS_API_KEY"));
httpPost.setEntity(new StringEntity(jsonBody));
try (CloseableHttpClient client = HttpClients.createDefault()) {
var response = client.execute(httpPost);
String result = EntityUtils.toString(response.getEntity());
System.out.println("发送结果: " + result);
}
}
}
```
Node.js环境下,`axios`是目前最流行的HTTP客户端库,它提供了Promise API和自动JSON转换功能。以下是使用axios发送短信的完整示例:
```javascript
const axios = require('axios');
const https = require('https');
// API配置
const API_KEY = process.env.SMS_API_KEY;
const API_URL = 'https://www.lanlansms.com/v1/sms/send';
const SENDER_ID = 'SPREDG';
// 创建可复用的axios实例(推荐做法)
const smsClient = axios.create({
baseURL: API_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
// 对于高并发场景,可配置keepAlive
httpsAgent: new https.Agent({ keepAlive: true })
});
/**
* 发送单条短信
* @param {string} phoneNumber - 接收方手机号(含国家代码)
* @param {string} message - 短信内容
* @returns {Promise } API响应
*/
async function sendSms(phoneNumber, message) {
const payload = {
to: phoneNumber,
sender_id: SENDER_ID,
message: message,
type: 'transactional'
};
try {
const response = await smsClient.post('', payload);
console.log(`✅ 发送成功!Message ID: ${response.data.message_id}`);
return response.data;
} catch (error) {
if (error.response) {
// 服务端返回了错误状态码(4xx/5xx)
console.error(`❌ API错误: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
} else if (error.request) {
// 请求已发出但未收到响应(网络问题)
console.error(`❌ 网络错误: 未收到响应`);
} else {
console.error(`❌ 请求配置错误: ${error.message}`);
}
throw error;
}
}
// 批量发送(使用Promise.all并发)
async function sendBulkSms(recipients, message) {
const promises = recipients.map(phone => sendSms(phone, message));
const results = await Promise.allSettled(promises); // 使用allSettled避免单个失败中断全部
const succeeded = results.filter(r => r.status === 'fulfilled').length;
const failed = results.filter(r => r.status === 'rejected').length;
console.log(`批量发送完成: 成功 ${succeeded}, 失败 ${failed}`);
return results;
}
// 使用示例
sendSms('+919876543210', 'Your OTP is 654321')
.then(result => console.log('完成:', result))
.catch(err => console.error('失败:', err));
```
> **注意事项**:批量发送时,使用`Promise.allSettled()`而非`Promise.all()`可以确保单个请求失败不会导致整个批次中断。对于超大批量场景(如10,000条以上),建议使用队列或分批处理,避免瞬间并发过高触发服务商限流。
PHP开发者最常用的HTTP客户端是cURL扩展。以下代码使用cURL实现短信发送,并包含完整的错误处理:
```php
/**
* 发送短信的PHP函数
*
* @param string $phoneNumber 接收方手机号(含国家代码,如+919876543210)
* @param string $message 短信内容
* @return array API响应结果
*/
function sendSms($phoneNumber, $message) {
$apiKey = getenv('SMS_API_KEY');
$apiUrl = 'https://www.lanlansms.com/v1/sms/send';
$senderId = 'SPREDG';
// 构建请求数据
$payload = [
'to' => $phoneNumber,
'sender_id' => $senderId,
'message' => $message,
'type' => 'transactional'
];
$jsonPayload = json_encode($payload);
// 初始化cURL
$ch = curl_init($apiUrl);
// 设置cURL选项
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonPayload),
'Authorization: Bearer ' . $apiKey
]);
// 执行请求
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// 错误处理
if ($curlError) {
error_log("cURL错误: " . $curlError);
return ['error' => $curlError];
}
$result = json_decode($response, true);
if ($httpCode == 200) {
error_log("✅ 发送成功! Message ID: " . ($result['message_id'] ?? 'unknown'));
} else {
error_log("❌ 发送失败,HTTP状态码: $httpCode, 响应: $response");
}
return $result;
}
// Laravel框架中的Service封装示例
namespace App\Services;
use Illuminate\Support\Facades\Http;
class SmsService
{
protected $apiKey;
protected $apiUrl;
protected $senderId;
public function __construct()
{
$this->apiKey = config('sms.api_key');
$this->apiUrl = config('sms.api_url');
$this->senderId = config('sms.sender_id');
}
public function sendOtp($phoneNumber, $otp)
{
$response = Http::withToken($this->apiKey)
->timeout(10)
->post($this->apiUrl, [
'to' => $phoneNumber,
'sender_id' => $this->senderId,
'message' => "Your OTP is: {$otp}",
'type' => 'transactional'
]);
if ($response->successful()) {
return $response->json();
}
throw new \Exception('SMS发送失败: ' . $response->body());
}
}
// 调用示例
sendSms('+919876543210', 'Your OTP is 654321');
?>
```
> **Laravel用户提示**:Laravel 8.0及以上版本内置了优雅的HTTP Client,语法比cURL简洁得多。上述代码中展示了如何在Laravel Service类中封装短信发送逻辑。
Go语言的`net/http`标准库功能强大,足以满足短信API调用的需求。以下代码展示了完整的请求构造、错误处理和JSON解析:
```go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
// SmsRequest 定义请求体结构
type SmsRequest struct {
To string `json:"to"`
SenderID string `json:"sender_id"`
Message string `json:"message"`
Type string `json:"type"`
}
// SmsResponse 定义响应体结构
type SmsResponse struct {
Status string `json:"status"`
MessageID string `json:"message_id"`
CreditsUsed int `json:"credits_used"`
Error string `json:"error,omitempty"`
}
// SmsClient 短信客户端结构体(支持依赖注入)
type SmsClient struct {
apiKey string
apiURL string
senderID string
httpClient *http.Client
}
// NewSmsClient 创建短信客户端实例
func NewSmsClient(apiKey, apiURL, senderID string) *SmsClient {
return &SmsClient{
apiKey: apiKey,
apiURL: apiURL,
senderID: senderID,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
// SendSms 发送短信的核心方法
func (c *SmsClient) SendSms(phoneNumber, message string) (*SmsResponse, error) {
// 构造请求体
reqBody := SmsRequest{
To: phoneNumber,
SenderID: c.senderID,
Message: message,
Type: "transactional",
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("JSON序列化失败: %w", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", c.apiURL, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("创建请求失败: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.apiKey)
// 发送请求
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("HTTP请求失败: %w", err)
}
defer resp.Body.Close()
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %w", err)
}
// 解析响应
var smsResp SmsResponse
if err := json.Unmarshal(body, &smsResp); err != nil {
return nil, fmt.Errorf("JSON解析失败: %w", err)
}
if resp.StatusCode != http.StatusOK {
return &smsResp, fmt.Errorf("API返回错误状态码 %d: %s", resp.StatusCode, string(body))
}
fmt.Printf("✅ 发送成功!Message ID: %s\n", smsResp.MessageID)
return &smsResp, nil
}
func main() {
apiKey := os.Getenv("SMS_API_KEY")
if apiKey == "" {
fmt.Println("❌ 请设置环境变量 SMS_API_KEY")
return
}
client := NewSmsClient(
apiKey,
"https://www.lanlansms.com/v1/sms/send",
"SPREDG",
)
result, err := client.SendSms("+919876543210", "Your OTP is 654321")
if err != nil {
fmt.Printf("❌ 发送失败: %v\n", err)
return
}
fmt.Printf("发送结果: %+v\n", result)
}
```
> **设计要点**:上述代码将HTTP客户端封装为`SmsClient`结构体,支持依赖注入,便于单元测试。`http.Client`设置了30秒超时,生产环境中应根据实际网络情况调整。
| 服务商 | Python | Java | Node.js | PHP | Go | 认证方式 |
| 蓝蓝通信 | ✅ SDK | ✅ SDK | ✅ SDK | ✅ SDK | ✅ SDK | Bearer Token |
| Msg91 | ✅ SDK | ✅ SDK | ✅ SDK | ✅ SDK | ❌ | API Key + Hash |
| Textlocal | ✅ 示例 | ✅ 示例 | ✅ 示例 | ❌ | ✅ SDK | API Key |
| Twilio | ✅ SDK | ✅ SDK | ✅ SDK | ✅ SDK | ✅ SDK | Account SID + Auth Token |
数据来源:各服务商官方文档及GitHub代码库
6.2 如何选择合适的技术方案
| 场景 | 推荐方案 | 理由 |
| 快速原型验证 | cURL + 命令行测试 | 无需安装依赖,一行命令即可验证API连通性 |
| Web应用集成 | 服务商官方SDK | 开箱即用,内置重试、超时等生产级特性 |
| 高并发场景 | 原生HTTP客户端 + 连接池 | 更精细的资源控制,避免SDK额外开销 |
| 多服务商冗余 | 统一抽象层 + 原生HTTP | 便于在不同服务商之间切换,降低供应商锁定风险 |
| 无服务/边缘计算 | 原生HTTP客户端 | 云函数环境通常不支持第三方SDK,原生HTTP更通用 |
在所有语言的示例代码中,API密钥都通过环境变量读取,而不是硬编码在源代码中。以下是在不同环境中配置环境变量的方式:
```bash
Linux/macOS
export SMS_API_KEY="your_api_key_here"
Windows (CMD)
set SMS_API_KEY=your_api_key_here
Windows (PowerShell)
$env:SMS_API_KEY="your_api_key_here"
Docker
docker run -e SMS_API_KEY="your_api_key_here" your_app
```
对于短信API调用,建议实现指数退避重试策略:
```python
from time import sleep
def send_sms_with_retry(phone, message, max_retries=3):
for attempt in range(max_retries):
try:
return send_sms(phone, message)
except Exception as e:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt 1秒, 2秒, 4秒
print(f"第{attempt+1}次尝试失败,{wait_time}秒后重试...")
sleep(wait_time)
```
| HTTP状态码 | 含义 | 处理建议 |
| 200 | 成功 | 正常处理 |
| 400 | 请求参数错误 | 检查手机号格式、sender_id长度等 |
| 401 | 认证失败 | 验证API密钥是否正确、是否过期 |
| 403 | 权限不足 | 检查账户余额、DLT合规状态 |
| 429 | 请求过于频繁 | 实现退避重试,降低并发 |
| 500+ | 服务端错误 | 临时性问题,可重试 |
发送印度短信时,必须注意以下合规要点:
- **DLT合规**:所有商业短信必须通过DLT注册的sender_id和template_id发送。未备案的印度短信将被运营商网关直接拦截。
- **手机号格式**:印度号码必须以`+91`开头,且不要包含前导的`+`号之外的任何特殊字符。
- **短信类型**:交易短信(transactional)可24小时发送且穿透DND;促销短信(promotional)仅限9:00-21:00发送,且无法发送给注册了DND的用户。
本文提供了Python、Java、Node.js、PHP、Go五种主流编程语言的短信API代码示例,所有代码均基于标准的RESTful API设计,可在替换API端点和认证信息后直接使用。无论你选择哪家短信服务商,都可以参考本文的示例快速完成短信发送功能的开发。
| 语言 | 推荐HTTP库 | 核心优势 |
| Python | requests | 语法简洁,开发效率最高 |
| Java | OkHttp | 性能优秀,连接池管理完善 |
| Node.js | axios | Promise API,支持请求/响应拦截器 |
| PHP | cURL / Laravel HTTP Client | 生态成熟,框架集成度高 |
| Go | net/http | 标准库强大,并发性能卓越 |
选择适合你技术栈的实现方式,将示例代码中的API端点替换为实际服务商的地址,配置好认证信息,即可在几分钟内完成短信功能的集成。建议在上线前通过小批量测试验证送达率和速度,确保生产环境的稳定可靠。