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

Java 自定義 URL 協議:基於 URL 框架實現專有網絡協議

     編輯:Java 相關知識

引言:為什麼要自定義 URL 協議?

標準 URL 協議(HTTP、FTP、FILE 等)滿足大多數場景,但在特定業務中(如內部 RPC、專有數據傳輸),我們需要定義自己的協議標識符(如 oschina://、echo://)。直接使用未註冊的協議會拋出 MalformedURLException: unknown protocol。Java 的 java.net.URL 提供了成熟的協議處理框架,通過擴展 URLStreamHandlerFactory、URLStreamHandler、URLConnection 即可實現自定義協議。

核心架構:三大 SPI 接口

  1. URLStreamHandlerFactory:工廠接口,根據協議名創建對應的 URLStreamHandler。
  2. URLStreamHandler:處理器,負責生成具體的 URLConnection。
  3. URLConnection:連接器,封裝具體的通信協議邏輯(I/O 規範)。

實戰:實現 oschina:// 協議

1. 定義協議工廠

public class EchoURLStreamHandlerFactory implements URLStreamHandlerFactory {
    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        if ("echo".equals(protocol) || "oschina".equals(protocol)) {
            return new EchoURLStreamHandler();
        }
        return null;
    }
}

2. 實現協議處理器

public class EchoURLStreamHandler extends URLStreamHandler {
    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        return new EchoURLConnection(u);
    }
}

3. 核心:自定義 URLConnection(模擬 HTTP 協議)

此處演示基於 Socket 手動構造 HTTP 請求,實際可替換為 WebSocket、SMTP 等任意協議。

public class EchoURLConnection extends URLConnection {
    private Socket connection;
    private static final int DEFAULT_PORT = 80;

    public EchoURLConnection(URL url) { super(url); }

    @Override public synchronized InputStream getInputStream() throws IOException {
        if (!connected) connect();
        return connection.getInputStream();
    }
    @Override public synchronized OutputStream getOutputStream() throws IOException {
        if (!connected) connect();
        return connection.getOutputStream();
    }
    @Override public String getContentType() { return "text/plain"; }

    @Override public synchronized void connect() throws IOException {
        if (connected) return;
        int port = url.getPort();
        if (port < 0 || port > 65535) port = DEFAULT_PORT;
        connection = new Socket(url.getHost(), port);
        // Socket 參數優化
        connection.setTcpNoDelay(true);
        connection.setSoTimeout(30000);
        connection.setKeepAlive(true);
        // ... 其他 Socket 設置省略

        // 手動構造 HTTP POST 請求
        StringBuilder req = new StringBuilder();
        req.append("POST ").append(url.getPath()).append(" HTTP/1.1\r\n");
        req.append("Host: ").append(url.getHost());
        if (port != 80) req.append(":").append(port);
        req.append("\r\nConnection: keep-alive\r\n");
        req.append("Content-Type: application/x-www-form-urlencoded;charset=utf-8\r\n");
        String body = "name=zhangsan&password=123456";
        req.append("Content-Length: ").append(body.getBytes("UTF-8").length).append("\r\n\r\n");
        req.append(body);
        connection.getOutputStream().write(req.toString().getBytes("UTF-8"));
        connected = true;
    }
    @Override public synchronized void disconnect() throws IOException {
        if (connected) { connection.close(); connected = false; }
    }
}

4. 註冊與測試

public class TestCustomProtocol {
    public static void main(String[] args) throws Exception {
        URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory());
        URL url = new URL("oschina://localhost:8080/test/ios.php");
        EchoURLConnection conn = (EchoURLConnection) url.openConnection();
        conn.setDoOutput(true); conn.setDoInput(true);
        // 發送數據、讀取響應...
        // 處理 Chunked 編碼響應...
    }
}

進階:自定義 ContentHandler 解析 MIME 類型

實現 ContentHandler 並註冊 URLConnection.setContentHandlerFactory(),可自定義響應內容的解析邏輯(如直接返回首行文本)。

總結

Java URL 框架提供了標準化的協議擴展機制,核心在於實現三大 SPI 接口。自定義協議本質上是對 I/O 規範的封裝,靈活性極高,適用於私有協議、內部 RPC 等場景。

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