Java Socket搭建本地HTTP服务器时HTML关联静态资源加载失败问题
问题根因分析
- 请求路径映射缺失:浏览器加载完index.html后,会自动发送GET请求获取页面关联的资源,比如你的css文件对应请求路径是
/myStyles.css,你的代码仅对/路径做了映射到Resources/index.html的处理,其余路径直接用请求路径作为本地文件路径读取,系统找不到/myStyles.css这个根路径下的文件,自然抛出异常。 - 响应头格式不符合HTTP规范:HTTP协议要求响应头和响应体之间必须有空行,你之前的代码写完响应头直接传输文件内容,没有空行分隔,浏览器会解析异常。
- 响应头Content-Type固定错误:当前所有响应的
Content-Type都写死为text/html,即使后续资源请求通了,浏览器也会将css、图片等资源当做HTML文件解析,无法正常渲染样式和图片。 - ServerSocket创建逻辑不合理:你把
new ServerSocket(8080)放在了while死循环内部,每次处理完一个请求就关闭服务端口再重新监听,会导致并发请求处理异常。
修复方案
修改后完整代码
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class HttpServer { // 根据文件后缀返回对应Content-Type private static String getContentType(String fileName) { if (fileName.endsWith(".html") || fileName.endsWith(".htm")) { return "text/html; charset=UTF-8"; } else if (fileName.endsWith(".css")) { return "text/css; charset=UTF-8"; } else if (fileName.endsWith(".png")) { return "image/png"; } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { return "image/jpeg"; } else if (fileName.endsWith(".js")) { return "application/javascript; charset=UTF-8"; } else { return "application/octet-stream"; } } public static void main(String[] args) throws IOException { // ServerSocket移到循环外,只初始化一次 ServerSocket sSocket = new ServerSocket(8080); while (true) { Socket cSocket = sSocket.accept(); OutputStream oStream = cSocket.getOutputStream(); PrintWriter out = new PrintWriter(oStream, true); Scanner in = new Scanner(new InputStreamReader(cSocket.getInputStream())); // 解析请求行 String command = in.next(); String fileName = in.next(); String protocol = in.next(); // 路径映射处理:所有请求都映射到Resources目录下 if (fileName.equals("/")) { fileName = "Resources/index.html"; } else { // 去掉路径开头的/,拼上Resources前缀 fileName = "Resources/" + fileName.substring(1); } // 404异常处理 File file = new File(fileName); if (!file.exists()) { out.println("HTTP/1.1 404 Not Found"); out.println("Server: My Server"); out.println("Content-Type: text/html; charset=UTF-8"); // 响应头和响应体之间的空行 out.println(); out.println("<h1>404 资源不存在</h1>"); } else { FileInputStream fis = new FileInputStream(file); // 返回响应头 out.println("HTTP/1.1 200 OK"); out.println("Server: My Server"); out.println("Content-Type: " + getContentType(fileName)); // 响应头和响应体之间的空行,必须保留 out.println(); out.flush(); // 先将响应头刷出再传输二进制内容 fis.transferTo(oStream); fis.close(); } // 关闭资源 in.close(); out.close(); cSocket.close(); } } }
额外修正点
你index.html中的link标签属性写错了,content="text/css"需要改为type="text/css",否则浏览器可能无法正确识别样式文件:
<link rel="stylesheet" type="text/css" href="./myStyles.css"/>
你原本能正常读取index.html,说明IntelliJ运行配置的工作目录就是项目根目录,不需要额外修改IDE配置。
内容的提问来源于stack exchange,提问作者Jim Pham
相关产品推荐
相关产品推荐

