Apache HttpClient 封裝了 java.net 底層細節,提供優雅的流式 API。本文示範如何利用 Java 序列化機制,透過 HTTP POST 在客戶端與 Servlet 伺服器之間雙向傳輸任意 Serializable 物件,並搭配查詢字串傳遞額外參數。
InputStreamRequestEntity 發送;接收回應流並反序列化。request.getInputStream() 讀取物件,處理後將結果物件寫入 response.getOutputStream()。application/octet-stream,查詢字串傳遞簡單參數。import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import java.io.*;
public class ObjectTransferClient {
public static void main(String[] args) throws Exception {
String url = "https://localhost:8084/system/linantest";
String queryString = "test=hello";
String inputObj = " boy!";
Serializable result = sendObject(url, queryString, inputObj);
System.out.println("Server returned: " + result);
}
public static Serializable sendObject(String url, String queryString, Serializable inputObj) throws IOException {
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
post.setQueryString(queryString);
post.setRequestHeader("Content-Type", "application/octet-stream");
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(1024);
ObjectOutputStream objOut = null;
ByteArrayInputStream byteIn = null;
Serializable returnObj = null;
try {
// 序列化請求物件
objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(inputObj);
objOut.flush();
// 發送
byteIn = new ByteArrayInputStream(byteOut.toByteArray());
post.setRequestEntity(new InputStreamRequestEntity(byteIn));
client.executeMethod(post);
// 接收並反序列化回應
try (InputStream respStream = post.getResponseBodyAsStream();
ObjectInputStream objIn = new ObjectInputStream(respStream)) {
returnObj = (Serializable) objIn.readObject();
}
} catch (ClassNotFoundException e) {
throw new IOException("Deserialization failed", e);
} finally {
// 資源釋放
closeQuietly(objOut);
closeQuietly(byteIn);
post.releaseConnection();
}
return returnObj;
}
private static void closeQuietly(Closeable c) {
if (c != null) try { c.close(); } catch (IOException ignored) {}
}
}
package test.li;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class ObjectTransferServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
private void processRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String param = req.getParameter("test"); // 取得查詢字串參數
ObjectInputStream objIn = null;
ObjectOutputStream objOut = null;
try {
// 讀取客戶端傳來的物件
objIn = new ObjectInputStream(req.getInputStream());
Object received = objIn.readObject();
// 業務邏輯:簡單字串拼接示範
String responseObj = param + received.toString();
// 序列化回應物件
resp.setContentType("application/octet-stream");
objOut = new ObjectOutputStream(resp.getOutputStream());
objOut.writeObject(responseObj);
objOut.flush();
} catch (ClassNotFoundException e) {
throw new ServletException("Class not found during deserialization", e);
} finally {
closeQuietly(objIn);
closeQuietly(objOut);
}
}
private void closeQuietly(Closeable c) {
if (c != null) try { c.close(); } catch (IOException ignored) {}
}
}
serialVersionUID 一致),否則反序列化會拋 InvalidClassException。ByteArrayOutputStream 緩衝序列化資料,避免直接操作 Socket 輸出流造成半包問題。finally 區塊確保流與連線釋放,防止連線洩漏導致連線池耗盡。Serializable;若需版本演進,妥善規劃 serialVersionUID 策略。ObjectInputFilter,Java 9+)。HttpClient 配合 Java 序列化可快速實現物件級 RPC 風格通訊,適合內部可信系統整合。但對於對外服務或高安全要求場景,請採用標準化、語言無關的序列化格式並啟用嚴格的反序列化防護。