首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Servlet 手機 App 介面安全系列 (二):短信驗證碼接入實戰與平台選型避坑

     編輯:Java 相關知識

繼上篇 MD5 簽名驗證,本文實戰接入短信驗證碼功能,涵蓋平台選型對比、HTTP 客戶端兩種寫法 (原生 HttpURLConnection vs HttpClient)、參數組裝與編碼、回應解析 及常見坑點。

一、短信平台選型建議

學習/原型階段建議用提供測試帳號、HTTP API 直連的平台 (如 wasun.cn),避開 SDK 強綁與漫長審核。

二、HTTP 請求工具類 (原生 HttpURLConnection 版)

public class HttpRequest {
  /** GET 請求 */
  public static String sendGet(String url, String param) {
    StringBuilder result = new StringBuilder();
    try (BufferedReader in = new BufferedReader(
        new InputStreamReader(new URL(url + "?" + param).openStream(), StandardCharsets.UTF_8))) {
      String line;
      while ((line = in.readLine()) != null) result.append(line);
    } catch (Exception e) { e.printStackTrace(); }
    return result.toString();
  }

  /** POST 請求 (application/x-www-form-urlencoded) */
  public static String sendPost(String url, String param) {
    StringBuilder result = new StringBuilder();
    try {
      HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
      conn.setRequestMethod("POST");
      conn.setDoOutput(true);
      conn.setDoInput(true);
      conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
      conn.setRequestProperty("User-Agent", "Mozilla/4.0");
      conn.setConnectTimeout(5000);
      conn.setReadTimeout(10000);

      try (PrintWriter out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8))) {
        out.print(param);
        out.flush();
      }

      try (BufferedReader in = new BufferedReader(
          new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
        String line;
        while ((line = in.readLine()) != null) result.append(line);
      }
    } catch (Exception e) { e.printStackTrace(); }
    return result.toString();
  }
}

三、平台官方 HttpClient 3.x 範例 (舊版)

// 需 commons-httpclient-3.1.jar, commons-codec, dom4j
public class SmsSender {
  private static final String URL = "https://xxx/webservice/sms.php?method=Submit";

  public void send(String mobile, String code) throws Exception {
    HttpClient client = new HttpClient();
    PostMethod post = new PostMethod(URL);
    client.getParams().setContentCharset("UTF-8");
    post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");

    String content = "您的驗證碼是:" + code + "。請勿洩露。";
    NameValuePair[] data = {
      new NameValuePair("account", "用戶名"),
      new NameValuePair("password", "密碼"), // 或 MD5
      new NameValuePair("mobile", mobile),
      new NameValuePair("content", content)
    };
    post.setRequestBody(data);

    client.executeMethod(post);
    String xml = post.getResponseBodyAsString();
    // 解析 XML: 2提交成功xxx
    Document doc = DocumentHelper.parseText(xml);
    Element root = doc.getRootElement();
    System.out.println("code=" + root.elementText("code"));
    post.releaseConnection();
  }
}

四、Servlet 調用示範

@WebServlet("/sendSms")
public class SendSmsServlet extends HttpServlet {
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8");
    String mobile = req.getParameter("mobile");
    String code = String.valueOf((int)((Math.random()*9+1)*1000)); // 4位數

    // 組裝參數 (依平台文檔調整)
    String param = "account=xxx&password=yyy&mobile=" + mobile 
                 + "&content=" + URLEncoder.encode("您的驗證碼:" + code, "UTF-8")
                 + "&stime=&sign=&type=pt&extno=";

    String result = HttpRequest.sendPost("https://xxx/webservice/sms.php?method=Submit", param);
    // 解析 result (XML/JSON/HTML) 判斷是否成功
    resp.getWriter().write(result);
  }
}

五、關鍵坑點與避坑指南

  1. 參數名稱以平台 DEMO 為準:官方文檔常過時/錯誤,DEMO 代碼裡的 NameValuePair key 才是標準。
  2. 內容編碼:content 必須 URLEncoder.encode(..., "UTF-8"),且平台要求模板格式固定 (如「您的驗證碼是:【變量】」),不可隨意修改。
  3. 回應格式非標準 JSON:部分平台返回 HTML 片段或純文本,需用正則/Jsoup 解析,而非 JSONObject。
  4. 同步阻塞風險:HTTP 發送短信屬網路 I/O,建議放入線程池或消息隊列 (RabbitMQ/Kafka) 異步處理,避免阻塞 Servlet 線程。
  5. 頻率限制:同一手機號/同一 IP 分鐘/小時/天發送上限,需在業務層攔截 (Redis 計數器)。
  6. 測試號碼白名單:測試階段平台常限制只能發給綁定的測試手機號。

總結

短信驗證碼接入核心在於 參數組裝準確、編碼正確、回應解析健壯、異步非阻塞、頻率限制。學習階段選擇 HTTP API 直連、提供測試帳號的平台;生產環境轉向雲廠商 (阿里/騰訊/華為) 享受高達 99.9% 到達率與完善監控。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
平台優點缺點適合場景
ShareSDK價格低、最低充 100 元審核極嚴、需集成 SDK、上架需 20+ 天長期穩定、有 App 上架資質
萬商雲通訊 (wasun.cn)測試帳號秒達、無 SDK 強綁、HTTP API 直連正式模板需備案快速原型、測試、中小專案
阿里雲/騰訊雲穩定性高、API 規範、控制台完善實名認證、模板審核、價格較高生產環境、大流量