Java简易Web服务器OutputStream写入失败及连接问题求助
你的Web服务器代码问题分析与修复
核心错误点
- 未定义变量
thefile:你只定义了字符串类型的file,但后续使用的thefile是File对象,完全没声明,直接编译失败,服务器根本启动不起来,这是浏览器连不上的主要原因。 - 代码块闭合错误:处理完请求解析后多了一个
},导致后续写入响应的代码不在try块内,编译报错。 - 响应输出到控制台而非浏览器:
PrintWriter response = new PrintWriter(System.out);把HTTP响应打印到了服务器控制台,没有发送给客户端的Socket输出流,浏览器自然收不到内容。 - 请求读取逻辑存在空指针风险:
br.readLine()在流结束时会返回null,原代码的while (!line.isEmpty())会触发NullPointerException,导致连接异常中断。 - HTTP响应格式错误:响应头结束后缺少一个空行(
\r\n\r\n),浏览器无法区分响应头和响应体,即使收到数据也无法解析。 - 未处理文件不存在的场景:文件不存在时仅在控制台打印信息,没有给浏览器返回404错误响应,导致浏览器一直等待连接超时。
- 根路径请求未处理:当请求
localhost:50505时,file会是/,需要默认映射到某个文件(比如index.html),否则会尝试访问根目录,无法读取。
修正后的完整代码
package lab11; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.io.OutputStream; import java.io.PrintWriter; public class Main { // 修正类名,符合Java规范 private static final int LISTENING_PORT = 50505; // 建议使用相对路径,确保files目录在项目根目录下 private static final String ROOT_DIRECTORY = "./files"; public static void main(String[] args) { ServerSocket serverSocket; try { serverSocket = new ServerSocket(LISTENING_PORT); } catch (Exception e) { System.out.println("Failed to create listening socket."); e.printStackTrace(); return; } System.out.println("Listening on port " + LISTENING_PORT); try { while (true) { Socket connection = serverSocket.accept(); System.out.println("\nConnection from " + connection.getRemoteSocketAddress()); handleConnection(connection); } } catch (Exception e) { System.out.println("Server socket shut down unexpectedly!"); System.out.println("Error: " + e); System.out.println("Exiting."); } } public static void handleConnection(Socket sok) { try { InputStream one = sok.getInputStream(); InputStreamReader isr = new InputStreamReader(one); BufferedReader br = new BufferedReader(isr); StringBuilder request = new StringBuilder(); String line; // 修正读取逻辑,避免空指针 line = br.readLine(); while (line != null && !line.isEmpty()) { request.append(line + "\r\n"); line = br.readLine(); } String[] splitline = request.toString().split("\r\n"); String getLine = null; String filePath = "/"; // 默认请求根路径 for (String i : splitline) { if (i.startsWith("GET")) { // 更精准匹配GET请求行 getLine = i; String[] splitget = getLine.split(" "); if (splitget.length >= 2) { filePath = splitget[1]; } break; // 只处理第一行GET请求 } } // 处理根路径请求,默认返回index.html if (filePath.equals("/")) { filePath = "/index.html"; } // 构建File对象,修正变量未定义问题 File theFile = new File(ROOT_DIRECTORY + filePath); // 安全校验:防止路径遍历攻击,确保文件在根目录内 if (!theFile.getCanonicalPath().startsWith(new File(ROOT_DIRECTORY).getCanonicalPath())) { sendErrorResponse(sok.getOutputStream(), 403, "Forbidden"); return; } OutputStream socketOut = sok.getOutputStream(); if (theFile.exists() && theFile.isFile() && theFile.canRead()) { // 发送200响应头,输出流改为Socket的OutputStream PrintWriter responseWriter = new PrintWriter(socketOut); responseWriter.write("HTTP/1.1 200 OK\r\n"); responseWriter.write("Connection: close\r\n"); responseWriter.write("Content-Length: " + theFile.length() + "\r\n"); responseWriter.write("\r\n"); // 响应头结束的空行,必须添加 responseWriter.flush(); sendFile(theFile, socketOut); } else { // 给浏览器返回404错误响应 sendErrorResponse(socketOut, 404, "Not Found"); System.out.println("File not found: " + theFile.getAbsolutePath()); } } catch (Exception e) { System.out.println("Error while communicating with client: " + e); e.printStackTrace(); try { // 发生异常时返回500错误 sendErrorResponse(sok.getOutputStream(), 500, "Internal Server Error"); } catch (IOException ex) { // 忽略发送错误的异常 } } finally { try { sok.close(); } catch (Exception e) { } System.out.println("Connection closed."); } } private static void sendErrorResponse(OutputStream socketOut, int statusCode, String statusMsg) throws IOException { PrintWriter writer = new PrintWriter(socketOut); writer.write(String.format("HTTP/1.1 %d %s\r\n", statusCode, statusMsg)); writer.write("Connection: close\r\n"); writer.write("Content-Type: text/plain\r\n"); writer.write("Content-Length: " + statusMsg.length() + "\r\n"); writer.write("\r\n"); writer.write(statusMsg); writer.flush(); } private static void sendFile(File file, OutputStream socketOut) throws IOException { InputStream in = new BufferedInputStream(new FileInputStream(file)); OutputStream out = new BufferedOutputStream(socketOut); byte[] buffer = new byte[4096]; // 使用字节数组提高传输效率,替代单字节读取 int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } out.flush(); in.close(); } }
使用说明
- 在项目根目录下创建
files文件夹,放入测试文件(比如index.html)。 - 启动服务器后,访问
http://localhost:50505会返回files/index.html,访问http://localhost:50505/test.txt会返回files/test.txt。 - 如果文件不存在,浏览器会收到404错误提示。
内容的提问来源于stack exchange,提问作者Hoko L
相关产品推荐
相关产品推荐

