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

Node.js中发送HTML响应及处理请求响应的正确方式

原写法的问题
  • 服务创建逻辑位置错误:http.createServer仅需在服务启动阶段执行1次,放在fs.readFile回调中会导致服务启动依赖文件读取结果,后续要返回多文件时必然出现重复创建服务的冗余逻辑。
  • 无路由匹配逻辑:当前写法无论请求路径、请求方法是什么,都会固定返回同一个index.html内容,无法满足多页面响应需求。
  • 异常处理缺失:没有处理文件不存在、非法请求路径等场景的错误返回,也没有设置正确的字符编码,很容易出现中文乱码问题。
Node.js 发送HTML响应的标准原生实现

核心原则:服务全局只创建一次,请求触发时再根据请求信息匹配、读取对应文件返回,不要将服务实例初始化逻辑嵌入IO操作回调中。

可直接运行的参考实现:

const http = require('http');
const fs = require('fs');
const path = require('path');

// 静态HTML文件存放的根目录
const HTML_ROOT = path.resolve(__dirname, '../Html');

// 服务仅初始化一次
const server = http.createServer((req, res) => {
  // 只处理GET类型的页面请求
  if (req.method !== 'GET') {
    res.statusCode = 405;
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    return res.end('请求方法不允许');
  }

  // 路由匹配:访问根路径默认返回index.html,其他路径按url匹配对应文件
  const reqPath = req.url === '/' ? '/index.html' : req.url;
  // 拼接得到目标文件的绝对路径
  const targetPath = path.join(HTML_ROOT, reqPath);

  // 路径安全校验:防止目录遍历攻击,禁止访问HTML根目录之外的文件
  if (!targetPath.startsWith(HTML_ROOT)) {
    res.statusCode = 403;
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    return res.end('<h1>403 禁止访问</h1>');
  }

  // 请求到来时再读取目标文件返回
  fs.readFile(targetPath, (err, fileData) => {
    if (err) {
      // 文件不存在返回404
      if (err.code === 'ENOENT') {
        res.statusCode = 404;
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        return res.end('<h1>404 页面不存在</h1>');
      }
      // 其他读取错误返回500
      res.statusCode = 500;
      res.setHeader('Content-Type', 'text/html; charset=utf-8');
      return res.end('<h1>500 服务器内部错误</h1>');
    }

    // 正常返回HTML内容,明确设置utf-8编码避免乱码
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end(fileData);
  });

  console.log('收到请求:', req.method, req.url);
});

// 启动监听,不需要等待文件读取操作
server.listen(3000, 'localhost', () => {
  console.log('服务已启动,监听 localhost:3000');
});
实践建议
  • 原生手写HTTP服务仅适合学习底层原理,生产环境直接使用成熟框架即可,不需要重复造轮子:比如Express可以直接用express.static中间件托管静态HTML文件,Koa可以用koa-static中间件,内置了路径安全、缓存控制、MIME类型自动识别等能力,稳定性更高。
  • 不要在请求处理流程中使用fs.existsSync、fs.readFileSync这类同步IO方法,会阻塞Node.js事件循环,导致服务并发能力大幅下降。
  • 返回HTML响应时必须在Content-Type头中声明charset=utf-8,否则页面中的中文内容会出现乱码。

内容的提问来源于stack exchange,提问作者Isa Özsoy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:03:28