You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

浏览器无法接收服务器响应:自制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";
    }
}

修复说明

  1. 添加响应头:在写入文件内容前,先发送HTTP/1.1 200 OK状态行,然后是Content-Type(根据文件类型设置)和Content-Length(文件的字节长度),最后用一个空行\r\n分隔响应头和响应体,这是HTTP协议的硬性要求。
  2. 文件类型适配:新增了getContentType方法,根据请求的URI后缀返回对应的Content-Type,确保浏览器能正确解析不同类型的资源(比如xml文件会被识别为xml类型)。
  3. 异常处理增强:在catch块中添加了500错误的响应逻辑,这样即使服务器内部出错,也能给浏览器返回明确的错误响应,而不是让用户一直等待无响应。

这样修改后,访问存在的index.xml时,服务器会先发送完整的HTTP响应头,再发送文件内容,浏览器就能正常接收并解析响应了。

内容的提问来源于stack exchange,提问作者Rongze Zhao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:21:38