浏览器无法接收服务器响应:自制Web服务器静态资源返回异常排查
问题诊断与修复方案
我一眼就看出问题所在了——你的代码在处理存在的静态资源时,只向输出流写入了文件内容,却完全没有发送HTTP响应的头部信息!浏览器在收到响应内容之前,必须先接收到正确的HTTP状态行和响应头,否则它会一直等待服务器发送完整的响应,这就是为什么访问存在的资源时服务器看起来“无响应”,而404情况因为你完整构造了响应头和内容,所以能正常显示。
具体问题点
看这段处理存在文件的代码:
if(file.exists()){ fis = new FileInputStream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch!=-1){ output.write(bytes,0,ch); ch = fis.read(bytes,0,BUFFER_SIZE); } }
这里直接把文件内容写入输出流,但没有先发送HTTP/1.1 200 OK状态行,也没有Content-Type、Content-Length这些必要的响应头,浏览器无法识别这是一个完整的HTTP响应,所以会一直处于等待状态。
修复后的代码
我们需要在写入文件内容之前,先构造并发送正确的HTTP响应头。另外,针对xml文件,要设置正确的Content-Type为application/xml,当然也可以做一个简单的文件类型映射来适配更多资源类型:
public class Response { public static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { File file = new File(HttpServer.WEB_ROOT, request.getUri()); if(file.exists()){ fis = new FileInputStream(file); // 1. 先发送HTTP响应头 String contentType = getContentType(request.getUri()); long fileLength = file.length(); String responseHeader = "HTTP/1.1 200 OK\r\n" + "Content-Type: " + contentType + "\r\n" + "Content-Length: " + fileLength + "\r\n" + "\r\n"; // 空行分隔响应头和内容 output.write(responseHeader.getBytes()); // 2. 再发送文件内容 int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch!=-1){ output.write(bytes,0,ch); ch = fis.read(bytes,0,BUFFER_SIZE); } }else { String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-type: text/html\r\n" + "Content-length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; output.write(errorMessage.getBytes()); } } catch (Exception e) { System.out.println(e.toString()); // 补充500错误响应逻辑 String errorMessage = "HTTP/1.1 500 Internal Server Error\r\n" + "Content-type: text/html\r\n" + "Content-length: 29\r\n" + "\r\n" + "<h1>Internal Server Error</h1>"; output.write(errorMessage.getBytes()); }finally { if(fis!=null){ fis.close(); } } } // 简单的文件类型映射方法 private String getContentType(String uri) { if(uri.endsWith(".xml")){ return "application/xml"; }else if(uri.endsWith(".html") || uri.endsWith(".htm")){ return "text/html"; }else if(uri.endsWith(".css")){ return "text/css"; }else if(uri.endsWith(".js")){ return "application/javascript"; } // 默认返回二进制类型 return "application/octet-stream"; } }
修复说明
- 添加响应头:在写入文件内容前,先发送
HTTP/1.1 200 OK状态行,然后是Content-Type(根据文件类型设置)和Content-Length(文件的字节长度),最后用一个空行\r\n分隔响应头和响应体,这是HTTP协议的硬性要求。 - 文件类型适配:新增了
getContentType方法,根据请求的URI后缀返回对应的Content-Type,确保浏览器能正确解析不同类型的资源(比如xml文件会被识别为xml类型)。 - 异常处理增强:在catch块中添加了500错误的响应逻辑,这样即使服务器内部出错,也能给浏览器返回明确的错误响应,而不是让用户一直等待无响应。
这样修改后,访问存在的index.xml时,服务器会先发送完整的HTTP响应头,再发送文件内容,浏览器就能正常接收并解析响应了。
内容的提问来源于stack exchange,提问作者Rongze Zhao
相关产品推荐
相关产品推荐

