如何在/home路由正确提供带样式的静态文件?Java HttpServer问题
问题
根目录为TodoList,包含TodoList/Views/index.html和style.css文件。期望在/home路由下提供这两个文件,但访问localhost:8080/home时仅加载HTML内容,CSS样式丢失。现有代码如下:
import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpExchange; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class App { public static void main(String[] args) throws IOException { int port = 8080; HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/home", new RequestHandler()); server.start(); System.out.println("Server started on port " + port); } } class RequestHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { String requestPath = exchange.getRequestURI().getPath(); if (requestPath.equals("/home")) { serveFile(exchange, "Views/index.html", "text/html"); serveFile(exchange, "Views/style.css", "text/css"); } else { // Handle other requests here // For example, you could serve a 404 page String response = "404 - Not Found"; exchange.sendResponseHeaders(404, response.length()); try (OutputStream os = exchange.getResponseBody()) { os.write(response.getBytes()); } } } private void serveFile(HttpExchange exchange, String filePath, String contentType) throws IOException { Path path = Paths.get(filePath); byte[] fileBytes = Files.readAllBytes(path); exchange.getResponseHeaders().set("Content-Type", contentType); exchange.sendResponseHeaders(200, fileBytes.length); try (OutputStream os = exchange.getResponseBody()) { os.write(fileBytes); } } }
问题原因
- 重复响应错误:一个HTTP请求只能对应一个响应。当前代码在处理
/home请求时连续调用两次serveFile,第一次发送HTML响应后,第二次尝试发送CSS响应会触发异常,导致CSS无法正常返回。 - 路由未覆盖CSS请求:浏览器加载HTML后,会自动发起CSS文件请求(若HTML中引用
style.css,实际请求路径为/home/style.css),但当前代码仅处理/home路径,其他路径直接返回404,导致CSS请求失败。
修复方案
调整路由逻辑,让服务器能够处理/home(返回HTML)和/home/style.css(返回CSS)两种请求,同时保证每个请求仅返回一个响应。
以下是优化后的代码(单Handler处理所有子路径):
import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class App { public static void main(String[] args) throws IOException { int port = 8080; HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/home", new RequestHandler()); server.start(); System.out.println("Server started on port " + port); } } class RequestHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { String requestPath = exchange.getRequestURI().getPath(); String targetFile = null; String contentType = null; // 匹配请求路径,分配对应的文件和内容类型 if (requestPath.equals("/home") || requestPath.equals("/home/")) { targetFile = "Views/index.html"; contentType = "text/html"; } else if (requestPath.equals("/home/style.css")) { targetFile = "Views/style.css"; contentType = "text/css"; } else { // 未知路径返回404 sendErrorResponse(exchange, 404, "404 - Not Found"); return; } Path file = Paths.get(targetFile); // 检查文件是否存在 if (!Files.exists(file)) { sendErrorResponse(exchange, 404, "404 - File Not Found"); return; } // 读取文件并发送响应 byte[] fileContent = Files.readAllBytes(file); exchange.getResponseHeaders().set("Content-Type", contentType); exchange.sendResponseHeaders(200, fileContent.length); try (OutputStream output = exchange.getResponseBody()) { output.write(fileContent); } } // 封装错误响应发送逻辑 private void sendErrorResponse(HttpExchange exchange, int code, String message) throws IOException { exchange.sendResponseHeaders(code, message.length()); try (OutputStream output = exchange.getResponseBody()) { output.write(message.getBytes()); } } }
额外注意事项
- 确保HTML中的CSS引用路径正确,应写为:
<link rel="stylesheet" href="/home/style.css">,这样浏览器才会请求正确的路由地址。 - 添加了文件存在性检查,避免因文件丢失导致的运行时异常。
内容的提问来源于stack exchange,提问作者Aliayub Ali
相关产品推荐
相关产品推荐

