Java中HttpURLConnection发POST请求遇EOFException问题排查
问题原因分析
你遇到的EOFException核心原因是客户端和服务器的通信协议不匹配:
- 客户端使用
HttpURLConnection发送的是标准HTTP协议请求,会自动在你写入的序列化数据前添加HTTP请求头(比如POST / HTTP/1.1、Content-Type等字段)。 - 服务器直接用
ObjectInputStream读取原始TCP流,而ObjectInputStream在构造时会尝试读取Java序列化格式的魔数(0xACED开头的字节),但此时流的开头是HTTP头内容,根本不是序列化数据,导致读取失败抛出EOFException。
解决方案
根据你的需求(必须使用ObjectInputStream),提供两种可行方案:
方案一:客户端改用原始Socket通信(推荐,协议匹配)
放弃HttpURLConnection,直接用Java Socket和服务器的ServerSocket对接,两端都使用原始TCP流+Java序列化格式,完全匹配:
int serverPort = 9876; String serverHost = "localhost"; Object payload = "Test payload"; Socket socket = null; try { socket = new Socket(serverHost, serverPort); ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(payload); objectOutputStream.flush(); objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
服务器代码无需修改,即可正常读取序列化的字符串。
方案二:服务器先解析HTTP请求头,再读取序列化数据
如果必须保留客户端的HttpURLConnection,服务器需要先读取并跳过HTTP请求头,直到读到HTTP头结束的空行,再用ObjectInputStream读取请求体中的序列化数据:
private static ServerSocket server; private static int port = 9876; public static void main(String[] args) throws IOException, ClassNotFoundException { server = new ServerSocket(port); while(true){ System.out.println("Waiting for the client request"); Socket socket = server.accept(); BufferedReader headerReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; // 读取HTTP请求头,直到空行(头结束标志) while ((line = headerReader.readLine()) != null && !line.isEmpty()) { System.out.println("HTTP Header: " + line); } // 此时流的位置已经到请求体,创建ObjectInputStream读取序列化数据 ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); Object object = objectInputStream.readObject(); if (object instanceof String) { String payload = (String) object; System.out.println("Payload received from client: " + payload); } objectInputStream.close(); socket.close(); } }
同时客户端需要修改Content-Type为序列化数据对应的类型(避免HTTP协议的歧义):
// 替换原有的Content-Type设置 connection.setRequestProperty("Content-Type", "application/java-serialized-object");
注意事项
- Java序列化仅适用于Java客户端和Java服务器的场景,跨语言不兼容,若后续有跨语言需求需考虑其他序列化方案(比如JSON)。
- 无论哪种方案,都要确保流的关闭顺序正确,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Giovanni
相关产品推荐
相关产品推荐

