Java SE 6 在網絡編程領域引入重量級增強,圍繞 HTTP 協議提供企業級認證支援、嵌入式 HTTP 服務、標準化 Cookie 管理、增強型網絡介面檢測與國際化域名 (IDN) 支援。本文逐項深度解析並提供實戰代碼。
import java.net.*;
public class NtlmAuthenticator extends Authenticator {
private final String username;
private final String domain;
private final String password;
public NtlmAuthenticator(String domain, String username, String password) {
this.domain = domain;
this.username = username;
this.password = password;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 格式:DOMAIN/username
String credential = domain + "/" + username;
return new PasswordAuthentication(credential, password.toCharArray());
}
}
// 使用方式
Authenticator.setDefault(new NtlmAuthenticator("CORP", "admin", "secret123"));
URL url = new URL("https://sharepoint.corp.intra/sites/team");
URLConnection conn = url.openConnection();
// 透明觸發 NTLM 握手
InputStream in = conn.getInputStream();
設定 http.auth.ntlm.domain=CORP 後,getPasswordAuthentication() 僅需返回用戶名密碼,框架自動拼接域前綴。
GSS/SPNEGO (Kerberos) → Digest → NTLM → Basic
HttpServerProvider:SPI 提供者,獲取實現HttpServer:服務器實例,綁定端口、註冊上下文HttpContext:路徑映射 (如 /myapp/)HttpHandler:請求處理介面 handle(HttpExchange)HttpExchange:封裝請求/響應、輸入輸出流、Headersimport com.sun.net.httpserver.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
public class MiniHttpServer {
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(7778), 0);
// 註冊上下文
server.createContext("/api/hello", exchange -> {
String response = "{\"message\":\"Hello, Java SE 6 HTTP Server!\"}";
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=UTF-8");
exchange.sendResponseHeaders(200, response.getBytes("UTF-8").length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes("UTF-8"));
}
});
server.createContext("/api/echo", exchange -> {
String method = exchange.getRequestMethod();
String body = new String(exchange.getRequestBody().readAllBytes(), "UTF-8");
String response = String.format("{\"method\":\"%s\",\"body\":\"%s\"}", method, body);
exchange.sendResponseHeaders(200, response.getBytes("UTF-8").length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes("UTF-8"));
}
});
server.setExecutor(Executors.newCachedThreadPool());
server.start();
System.out.println("HTTP Server started on port 7778");
System.out.println("GET https://localhost:7778/api/hello");
System.out.println("POST https://localhost:7778/api/echo");
}
}
CookieHandler (抽象基類)
└── CookieManager (預設實現)
├── CookieStore (存儲/檢索) → 内存實現 / 持久化實現
└── CookiePolicy (接受策略) → ACCEPT_ALL / ACCEPT_NONE / ACCEPT_ORIGINAL_SERVER
| 類/介面 | 核心職責 |
|---|---|
HttpCookie | 封裝 Cookie 屬性:name、value、domain、path、maxAge、secure、httpOnly、version (支援 Netscape/RFC2109/RFC2965) |
CookieStore | add(URI, HttpCookie)、get(URI)、getCookies()、getURIs()、自動清理過期 Cookie |
CookiePolicy | shouldAccept(URI, HttpCookie) 判定是否接受 |
CookieManager | 整合 Store + Policy,實現 CookieHandler 契約 |
import java.net.*;
import java.util.List;
public class CookieDemo {
public static void main(String[] args) throws Exception {
// 1. 建立自定義 Manager:接受所有 Cookie
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager); // 設為全域預設
// 2. 模擬首次請求:Server 返回 Set-Cookie
URL url = new URL("https://httpbin.org/cookies/set/sessionid/abc123");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.getInputStream().close(); // 觸發請求,Cookie 自動存入 Store
// 3. 後續請求:自動攜帶 Cookie
URL url2 = new URL("https://httpbin.org/cookies");
HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn2.getInputStream()))) {
System.out.println("Server 回應 (含自動攜帶 Cookie):");
String line;
while ((line = br.readLine()) != null) System.out.println(line);
}
// 4. 程式化操作 Cookie Store
CookieStore store = manager.getCookieStore();
for (URI uri : store.getURIs()) {
System.out.println("Domain: " + uri.getHost());
for (HttpCookie cookie : store.get(uri)) {
System.out.printf(" %s=%s [Path:%s, MaxAge:%d, Secure:%b]%n",
cookie.getName(), cookie.getValue(), cookie.getPath(),
cookie.getMaxAge(), cookie.getSecure());
}
}
}
}
Java SE 6 新增實用方法:
| 方法 | 返回值 | 用途 |
|---|---|---|
isUp() | boolean | 介面啟動且運行中 |
isLoopback() | boolean | 回環介面 (127.0.0.1) |
isPointToPoint() | boolean | 點對點鏈路 (PPP/VPN) |
supportsMulticast() | boolean | 支援多播 (IGMP) |
getHardwareAddress() | byte[] | MAC 位址 (6 bytes) |
getMTU() | int | 最大傳輸單元 (通常 1500) |
isVirtual() | boolean | 虛擬介面 (Docker/VM/Hyper-V) |
NetworkInterface.getNetworkInterfaces().asIterator()
.forEachRemaining(ni -> {
try {
if (ni.isUp() && !ni.isLoopback() && ni.getHardwareAddress() != null) {
String mac = bytesToHex(ni.getHardwareAddress());
System.out.printf("%s: %s (MTU:%d, Virtual:%b)%n",
ni.getDisplayName(), mac, ni.getMTU(), ni.isVirtual());
}
} catch (SocketException e) { e.printStackTrace(); }
});
RFC 3490/5890 定義 Unicode 域名轉 ASCII (Punycode) 算法:
import java.net.IDN;
public class IdnDemo {
public static void main(String[] args) {
String unicodeDomain = "例子.测试"; // 中文域名
String asciiDomain = IDN.toASCII(unicodeDomain);
// 輸出: xn--fsq092a.xn--0zwm56d
String recovered = IDN.toUnicode(asciiDomain);
// 輸出: 例子.测试
System.out.println("Unicode: " + unicodeDomain);
System.out.println("ASCII (Punycode): " + asciiDomain);
System.out.println("Recovered: " + recovered);
// 驗證合法性
try {
IDN.toASCII("invalid..domain"); // 拋出 IllegalArgumentException
} catch (IllegalArgumentException e) {
System.out.println("非法域名格式");
}
}
}
| 特性 | Java 5 | Java 6 | Java 7+ |
|---|---|---|---|
| NTLM 認證 | 不支援 | 原生支援 | 增強 (SPNEGO/Kerberos 更穩) |
| HTTP Server | 無 | com.sun.net.httpserver | 標準化 (JEP 274 jdk.httpserver) |
| Cookie 管理 | 僅抽象類 | 完整實現 | 持久化 Store (File/DB) |
| NetworkInterface | 基礎枚舉 | 狀態/屬性檢測 | 更多硬體屬性 |
| IDN | 無 | toASCII/toUnicode | UTS #46 相容 |
Java SE 6 的網絡增強解決了企業級集成中的三大痛點:Windows 域認證互操作、零依賴 HTTP 端點構建、標準化會話狀態管理。配合網絡介面深度檢測與國際化域名支援,使 Java 成為真正的「網絡編程第一方語言」。現代項目雖多遷移至 Java 11/17/21,但這些 API 設計哲學與核心類結構延續至今,深入理解其機制仍是高階網絡編程的必修課。