不装 Express 也能起服务:用 Node 原生 http 写个静态文件服务器

举报
海是岛思念的泪 发表于 2026/09/22 19:23:25 2026/09/22
【摘要】 Node 原生 http 起静态服务

本地想预览一下写好的网页、或者内网同事要拷个文件,不一定非要装 Express。Node 自带的 http、fs、path 三个核心模块,加起来十几行就能起一个静态文件服务器,把某个目录下的 html、css、js、图片直接吐给浏览器。我平时联调前端、临时给同事发个 demo,经常用这招,比 npm install 一个框架快多了。下面这段代码是我压过、跑通过的版本,路径穿越那道闸也专门处理过。

一、核心代码

思路很直接:收到请求,取出路径,拼到根目录,读文件返回,顺便按后缀设置 Content-Type。

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

const root = path.resolve(__dirname, 'public');
const types = { '.html':'text/html', '.js':'text/javascript', '.css':'text/css', '.png':'image/png' };

const server = http.createServer((req, res) => {
  const urlPath = decodeURIComponent(req.url.split('?')[0]);
  const rel = urlPath === '/' ? 'index.html' : urlPath.replace(/^\/+/, '');
  const file = path.resolve(root, rel);
  if (file !== root && !file.startsWith(root + path.sep)) {
    res.writeHead(403);
    return res.end('forbidden');
  }
  fs.readFile(file, (err, data) => {
    if (err) { res.writeHead(404); return res.end('not found'); }
    res.writeHead(200, { 'Content-Type': types[path.extname(file)] || 'application/octet-stream' });
    res.end(data);
  });
});
server.listen(3000, () => console.log('服务在 http://localhost:3000'));

逐行看:path.resolve(__dirname, ‘public’) 把根目录定死成脚本旁边的 public 文件夹,避免相对路径乱飘。urlPath 先用 decodeURIComponent 解码,不然路径里带中文或 %20 会出问题;再去掉问号后面的查询参数,只留路径。根路径 / 映射到 index.html,这是静态服务器的惯例。file 用 path.resolve(root, rel) 算出绝对路径,下面立刻校验它是不是真的落在 root 里。最后 readFile 读出来,按后缀给 Content-Type。

二、路径穿越防护不能省

这是最关键的一道安全闸。用户完全可以传 /…/server.js 甚至 /…/…/etc/passwd 这种路径,如果不拦,就能读到目录外的文件,等于把服务器裸奔给别人。我这里的做法是:先用 path.resolve 把请求路径拼成绝对路径,再判断它是不是以 root + path.sep 开头(或者刚好等于 root)。不是的话直接返回 403,绝不读文件。注意一定要先 resolve 再判断,别用字符串 contains 糊弄,因为 …/ 会骗过字符串判断。

三、更多踩坑提醒

第一,Content-Type 没设对,浏览器会把 js 当附件下载、把 css 当纯文本,页面直接废。常见类型我都列在 types 里了,匹配不到的后备成 application/octet-stream,至少不会乱执行。

第二,大文件用 readFile 会一次性读进内存。几 MB 没问题,上百 MB 建议换 fs.createReadStream 流式返回,边读边发,内存才稳。本地小工具无所谓,真传大文件得改。

第三,没有缓存、没有 gzip、没有并发优化。每次请求都重新读盘、返回不带 Cache-Control,重复访问也全量传。本地用用没事,扛量别靠它。

第四,它只支持 GET,POST、带路由的接口一概没有。要这些还是上 Express 静态中间件,或者干脆 Nginx,别拿演示代码当生产服务器。

四、怎么跑起来

项目里建一个 public 目录,里面放 index.html,node 跑这个脚本,浏览器开localhost:3000就能看到。换端口改 listen 的数字就行。想指定别的根目录,把 public 换成你的文件夹路径。

五、小结

十几行起一个静态服务,适合本地调试和临时分享文件,省去装框架。记住两件大事:防路径穿越、补 Content-Type。要正式部署、要扛并发、要大文件,交给 Nginx 或 Express 的静态中间件,这个脚本就当顺手的小工具。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。