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

J2ME 設備上實現 HTTP 協議通訊完整指南

     編輯:Java 相關知識

前言

隨著功能手機、早期智慧手機普及,MIDP 2.0 成為移動 Java 開發標準。受限於 CLDC/MIDP 沙箱與有限資源,javax.microedition.io 提供的 Generic Connection Framework (GCF) 是唯一網路 API。本文詳細講解 HttpConnection 實現 GET/POST 請求、資料流處理、MIDlet 完整範例及常見陷阱。

GCF 架構與 HttpConnection

Connection (介面)
 ├─ StreamConnection
 │    ├─ ContentConnection
 │    │    └─ HttpConnection  ← MIDP 強制實現
 │    └─ ...
 └─ DatagramConnection

關鍵點:

  • Connector.open(url) 為統一進入點,返回具體 Connection 子型別
  • HttpConnection 繼承 ContentConnection,支援 GET/POST/HEAD、請求標頭、回應碼、Content-Length
  • 所有 I/O 操作可能拋出 IOException,必須捕獲處理

發送 HTTP GET 請求

public String sendHttpGet(String url) throws IOException {
    HttpConnection conn = null;
    DataInputStream dis = null;
    StringBuffer response = new StringBuffer();
    
    try {
        // 1. 建立連線(預設 GET、READ_ONLY)
        conn = (HttpConnection) Connector.open(url);
        
        // 2. 獲取輸入流讀取回應
        dis = new DataInputStream(conn.openInputStream());
        
        int ch;
        while ((ch = dis.read()) != -1) {
            response.append((char) ch);
        }
    } finally {
        // 3. 釋放資源(順序:流 → 連線)
        if (dis != null) dis.close();
        if (conn != null) conn.close();
    }
    return response.toString();
}

發送 HTTP POST 請求

public String sendHttpPost(String url, String postData) throws IOException {
    HttpConnection conn = null;
    DataInputStream dis = null;
    DataOutputStream dos = null;
    StringBuffer response = new StringBuffer();
    
    try {
        // 1. 指定 READ_WRITE 模式
        conn = (HttpConnection) Connector.open(url, Connector.READ_WRITE);
        
        // 2. 設定 POST 方法
        conn.setRequestMethod(HttpConnection.POST);
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postData.getBytes().length));
        
        // 3. 寫入請求體
        dos = conn.openDataOutputStream();
        dos.write(postData.getBytes());
        dos.flush(); // 部分實現需 flush 觸發發送
        
        // 4. 讀取回應
        dis = new DataInputStream(conn.openInputStream());
        int ch;
        while ((ch = dis.read()) != -1) {
            response.append((char) ch);
        }
    } finally {
        if (dos != null) dos.close();
        if (dis != null) dis.close();
        if (conn != null) conn.close();
    }
    return response.toString();
}

關鍵差異點

步驟GETPOST
Connector.open 模式預設 (READ)Connector.READ_WRITE
設定請求方法無需(預設 GET)conn.setRequestMethod(HttpConnection.POST)
發送資料無DataOutputStream 寫入 byte[]
Content-Type通常不需設定必須設定 (如 application/x-www-form-urlencoded)

完整 MIDlet 範例:HTTP 測試客戶端

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;

public class HttpTestMidlet extends MIDlet implements CommandListener {
    private Display display;
    private Form inputForm, resultForm;
    private TextField urlField;
    private StringItem resultField;
    private List methodList;
    private Command cmdSend, cmdExit, cmdBack;
    private static final String DEFAULT_URL = "https://httpbin.org/get"; // 測試端點
    
    public HttpTestMidlet() {
        display = Display.getDisplay(this);
        
        // 輸入畫面
        inputForm = new Form("HTTP Client");
        urlField = new TextField("URL:", DEFAULT_URL, 256, TextField.URL);
        inputForm.append(urlField);
        cmdSend = new Command("Send", Command.OK, 1);
        cmdExit = new Command("Exit", Command.EXIT, 2);
        inputForm.addCommand(cmdSend);
        inputForm.addCommand(cmdExit);
        inputForm.setCommandListener(this);
        
        // 方法選擇
        methodList = new List("Select Method", List.IMPLICIT);
        methodList.append("GET", null);
        methodList.append("POST", null);
        methodList.setCommandListener(this);
        
        // 結果畫面
        resultForm = new Form("Response");
        cmdBack = new Command("Back", Command.BACK, 1);
        resultForm.addCommand(cmdBack);
        resultForm.setCommandListener(this);
    }
    
    public void startApp() {
        display.setCurrent(inputForm);
    }
    
    public void commandAction(Command c, Displayable d) {
        if (c == cmdSend) {
            display.setCurrent(methodList);
        } else if (c == cmdExit) {
            destroyApp(true);
            notifyDestroyed();
        } else if (c == cmdBack) {
            display.setCurrent(inputForm);
        } else if (d == methodList && c == List.SELECT_COMMAND) {
            String url = urlField.getString();
            String result;
            if (methodList.getSelectedIndex() == 0) { // GET
                result = sendHttpGet(url);
            } else { // POST
                result = sendHttpPost(url, "param1=value1¶m2=value2");
            }
            resultForm.deleteAll();
            resultForm.append(new StringItem(null, result));
            display.setCurrent(resultForm);
        }
    }
    
    // ... sendHttpGet / sendHttpPost 方法同上 ...
    
    public void pauseApp() {}
    public void destroyApp(boolean unconditional) {}
}

實戰陷阱與解決方案

問題現象解決方案
HTTPS 失敗IOException: Certificate exception手機需匯入 CA 憑證;或使用 HTTP 端點測試
大資料截斷回應不完整分塊讀取;檢查 Content-Length;避免單次 read() 全量讀取
POST 參數亂碼中文參數伺服端解析錯誤URLEncoder.encode(value, "UTF-8") 編碼;設定 Content-Type charset
連線超時長時間無響應MIDP 無標準超時 API;需自行執行緒監控或使用 SocketConnection 實現
重定向處理301/302 無自動跳轉讀取 Location 標頭,手動發起新請求

效能優化建議

  1. 重用連線:HTTP/1.1 Keep-Alive 需伺服端支援,MIDP 實現不一,測試後決定
  2. 壓縮傳輸:請求標頭 Accept-Encoding: gzip,解壓回應體
  3. 非阻塞 I/O:耗時網路操作放入獨立執行緒,避免凍結 UI
  4. 資料序列化:優先 JSON (kXML/JSR-172) 或輕量二進制,避免 XML 解析開銷

從 J2ME 到現代移動開發的演進

J2ME/MIDP 歷史使命已終,但其 GCF 設計思想(統一連線介面、工廠模式、資源受限下的流式處理)深深影響後來的 Android HttpURLConnection、OkHttp、iOS NSURLSession。理解 MIDP 網路編程,有助於掌握移動網路通訊的本質約束:頻寬、延遲、電量、記憶體四重限制下的可靠傳輸。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved