主题
Express 概述(Day10 1/3)
本页对应 Day10_Node,共 7 段视频,约 1 小时 43 分。
学习目标
- 能够独立使用 Node.js
http模块创建并启动 HTTP 服务,在回调中读取请求 URL、请求方式、请求体,设置状态码、响应头并结束响应。 - 能够从用途、请求体、安全性、数据长度限制四个维度准确说明 GET 与 POST 的区别,并能结合示例判断应选择哪种请求方式。
- 能够基于 URL 路径与服务器静态资源目录的映射关系,使用
fs、path、url模块实现静态文件托管,并处理 404、500、中文路径解码及 Content-Type/MIME 类型设置。 - 能够完成 npm 项目初始化并安装 Express,使用
express()创建 HTTP 服务并通过listen启动服务。 - 能够使用
app.get、app.post编写简单路由,根据请求路径和请求方式返回不同响应,并使用res.send、res.sendFile完成响应。 - 能够对比原生
http与 Express 在创建服务、路由处理和静态资源托管上的实现差异,并说明 Express 封装带来的简化。
知识点
从 HTTP 服务三件事讲起
为什么需要:后面用 Express 之前,必须先知道原生 HTTP 服务到底替我们做了什么。转写里把昨天内容总结为三部分:创建服务、启动服务、在请求回调里取请求数据并组织响应。
怎么想:创建服务用 http.createServer,它返回服务对象;启动服务调用 listen 指定端口;createServer 的回调会在收到客户端请求时执行,并自动拿到请求对象 req 和响应对象 res。取数据包括客户端 IP、请求方式、URL、请求体;响应则包括状态码、响应头、响应体。
怎么做:
js
const http = require('http');
const server = http.createServer((req, res) => {
// req.url、req.method 等
res.end('ok');
});
server.listen(8080, () => {
console.log('HTTP server running on 8080');
});易错点:res.end() 表示结束响应,不写浏览器会一直转圈;请求体本质是读取流,POST 请求要一点点取再拼接;GET 请求常见数据在 URL 查询字符串里。
GET 与 POST 的区别
为什么需要:这是面试和开发都常见的问题,也决定表单、接口怎么传数据。
怎么想:一般 GET 用于向服务器请求数据,POST 用于向服务器提交数据;GET 请求报文一般没有请求体,POST 有请求体;GET 通过 URL 查询字符串传数据,完全可见,POST 放在请求体里默认不可见,所以一般认为 POST 更安全;GET 受 URL 长度限制,约 2K 到 4K,POST 理论上没有这个容量限制。
怎么做:表单 method 不写或写 get,会把输入项拼成查询字符串;写 post 才把数据放进请求体。服务端解析 GET 用 URL 的查询串,解析 POST 要读请求体流。
易错点:POST 只是“更安全”,不是绝对安全;用抓包工具仍可能看到请求体;GET 也能传少量数据,不要把它理解成完全不能传。
初步实现静态文件托管
为什么需要:前端写的 HTML、CSS、图片、视频要能被浏览器请求到,后端就要提供静态文件服务。
怎么想:所谓“静态”是从服务器角度看的——服务器不执行 HTML 里的代码,只把文件内容搬运给浏览器。最直观方案是拿到 URL 的 pathname,用 switch case 判断不同路径,再读对应文件。
怎么做:用 url.parse(req.url) 拿 pathname,根据路径读 public 下的文件:
js
const url = require('url');
const fs = require('fs');
const path = require('path');
const pathname = url.parse(req.url).pathname;
switch (pathname) {
case '/':
case '/index.html':
fs.readFile(path.resolve(__dirname, 'public/index.html'), (err, data) => {
if (err) { res.statusCode = 500; return res.end('500'); }
res.end(data);
});
break;
default:
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end('<h1>您访问的页面不存在</h1>');
}调试过程:访问首页后样式没了,打开 Network 发现浏览器解析 HTML 后还会继续请求 CSS、图片、视频等资源;每个资源都是新请求。若每个路径都写 case,文件一多就维护不了。
易错点:path.resolve 拼路径时,如果 pathname 以 / 开头,会被当成根目录,前面拼的 public 可能失效;此时可用 path.join,或去掉开头斜杠。
完整静态资源托管:拼接、解码与 MIME
为什么需要:不能为每个静态文件写一个 case。转写里的关键发现是:URL 路径和 public 目录结构可以对应起来,直接把 pathname 拼到静态目录后面即可。
怎么做:
js
const filename = path.join(__dirname, 'public', pathname);
fs.access(filename, (err) => {
if (err) {
res.statusCode = 404;
return res.end('404 Not Found');
}
fs.readFile(filename, (err, data) => {
if (err) {
res.statusCode = 500;
return res.end('500');
}
res.end(data);
});
});中文路径问题:浏览器会自动对中文路径编码,服务端按编码后的名字找不到文件,所以要用 decodeURI(filename) 解码。注意不要提前 res.end(),否则异步读文件还没回调,响应已结束。
MIME 类型:响应头应设置 Content-Type,告诉浏览器内容类型。转写中用 mimes.json 按扩展名取 MIME,取不到就给空,让浏览器自行识别。扩展名可用 pathname.lastIndexOf('.') 配合 slice 获取。
Express 介绍、安装与创建服务
为什么需要:原生写路由、读文件、设置响应头较繁琐,Express 是 Node 的 Web 开发框架,封装了 HTTP 服务创建、请求响应处理和路由。
怎么做:先 npm init -y,再 npm i express。创建服务:
js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('欢迎访问本网站');
});
app.listen(8080, () => {
console.log('HTTP server running on 8080');
});易错点:Express 不再像原生 HTTP 那样统一写一个 createServer 回调,而是用路由方法匹配;res.send 会自动补 Content-Type,中文一般不再乱码。
Express 简单路由演示
为什么需要:不同路径、不同请求方式要返回不同内容,这就是路由。
怎么做:app.get('/login', ...) 处理 GET 登录页,app.post('/login', ...) 处理 POST 提交;res.sendFile 可直接发送文件,内部处理读取失败等情况。路径仍建议用 path.resolve(__dirname, ...) 拼绝对路径。
js
app.get('/login', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public/login.html'));
});
app.post('/login', (req, res) => {
res.send('<h2>表单提交成功</h2>');
});易错点:只写 app.get 时,POST 到同一路径不会进入该回调;方法名对应请求方式,路径对应匹配规则。调试时先启动服务,再用浏览器 Network 看请求是否发出、命中哪个路由。
一、HTTP 服务:创建、启动、取请求与做响应
为什么需要: 后端要能接收浏览器请求,并按照请求内容返回数据;不掌握 http 模块,就不知道请求报文、响应报文和路由判断的底层流程。
怎么想: 转写稿把 HTTP 服务总结为三部分:创建服务、启动服务、在回调里处理请求和响应。createServer 的回调会在接收到请求时执行,Node 会管理并发请求;请求对象用来取数据,响应对象用来组响应。
怎么做:
js
const http = require('http');
const server = http.createServer((req, res) => {
// req:取请求数据;res:设置响应
});
server.listen(8080, () => console.log('HTTP server is running on 8080'));从请求中可取客户端 IP、请求方式 method、URL、请求体;URL 后的查询字符串可用 url 模块解析。POST 请求体本质是读取流,要监听 data 和 end 拼接。响应可设置 statusCode、statusMessage、setHeader,用 write 写响应体,最后必须 end。
易错点: listen 的回调是“启动成功”执行,不是“收到请求”执行;不写 res.end() 浏览器会一直转圈;状态码不要乱写,要按规范;请求体是流,不能当成普通字符串直接取。
二、GET 与 POST 的区别
为什么需要: 这是常见面试题,也决定数据放在 URL 还是请求体里。
怎么想: 转写稿总结四点:GET 一般用于从服务器获取数据,POST 一般用于向服务器提交数据;GET 请求报文一般没有请求体,POST 一般有请求体;GET 通过 URL 查询字符串传数据,默认可见,POST 放请求体里,默认不可见,所以一般认为更安全;GET 传数据受 URL 长度限制,约 2K 到 4K,POST 理论上没有容量限制。
怎么做: 已学手段里,GET 可直接在地址栏写查询字符串,表单 method 不写或写 GET 也会拼查询字符串;POST 可用表单 method="post" 提交,服务端从请求体流里取数据。
易错点: POST 不是绝对安全,只是默认不可见,抓包仍可能看到;GET 也能提交少量数据;POST 理论无限制但受底层 HTTP/TCP 等限制;不要只会背四点,要理解“一般用于”的规范含义。
三、静态资源托管:从 switch-case 到路径拼接
为什么需要: 浏览器请求 HTML 时会继续请求 CSS、JS、图片、视频和 favicon,若只给几个路径写 switch-case,请求一多就维护不了。
怎么想: 转写稿的调试过程很关键:最初用 switch-case 判断 /index.html、/learn.html、/videos.html,但浏览器解析 HTML 后会再发 CSS、JS、图片请求,全部 404。后来发现 URL 中的路径可以和 public 目录结构对应,直接把 pathname 拼到 public 后面即可。
怎么做:
js
const pathname = decodeURI(url.parse(req.url).pathname);
const filePath = path.join(__dirname, 'public', pathname);
fs.access(filePath, (err) => {
if (err) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html; charset=utf-8');
return res.end('您访问的页面不存在');
}
fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 500;
return res.end('服务器发生未知错误');
}
res.end(data);
});
});易错点: 转写稿踩过 path.resolve(__dirname, 'public', pathname) 的坑:pathname 以 / 开头时会被当成根目录,前面拼的全废;应改用 path.join。异步 readFile 没执行完不能在外层 end,否则响应提前结束。中文路径浏览器会自动编码,服务端要 decodeURI。文件不存在返回 404,读取失败返回 500。
四、MIME 类型与中文路径
为什么需要: 响应头 Content-Type 要告诉浏览器返回的是什么类型;不设置时浏览器可能自动识别,但 favicon 等文件可能识别不了而被下载。
怎么想: 转写稿用 mimes.json 保存“扩展名 → MIME 类型”的对应关系,根据文件扩展名取 MIME;扩展名可从最后一个点后截取,找不到时给空字符串,让浏览器自行处理。
怎么做:
js
const mimes = require('./mimes.json');
const ext = path.extname(pathname).slice(1);
res.setHeader('Content-Type', mimes[ext] || '');易错点: path.extname 带点,mimes 的键通常不带点,要 slice(1);找不到 MIME 不要设成 undefined;中文路径要解码;浏览器会自动请求 /favicon.ico,这是正常现象。
五、Express:封装后的 HTTP 服务与路由
为什么需要: 原生 http 写路径判断、静态托管、中文解码、MIME 很繁琐;Express 是第三方 Web 框架,封装了创建服务、拆请求、组响应和路由。
怎么想: 先 npm init -y 生成 package.json,再 npm i express。express() 返回值就是服务对象,用 app.get('/')、app.post('/login') 按“请求方式 + 路径”匹配;res.send 会自动加 Content-Type,中文不乱码;res.sendFile 内置读取文件,失败会自动处理。
怎么做:
js
const express = require('express');
const path = require('path');
const app = express();
app.get('/', (req, res) => res.send('欢迎访问本网站'));
app.get('/login', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public/login.html'));
});
app.post('/login', (req, res) => res.send('<h2>表单提交成功</h2>'));
app.listen(8080, () => console.log('HTTP server is running on 8080'));易错点: 先初始化项目再安装;app.get('/') 只处理根路径,不是所有路径;POST 要写 app.post,否则 GET 路由接不到;sendFile 的路径最好用 path.resolve(__dirname, ...),避免受命令行位置影响;res.send 与 res.end 类似,但前者会自动补响应头。
从原生 HTTP 服务复习切入:Express 到底解决什么问题
为什么需要:上一节用 Node 内置 http 模块写服务,虽然能跑,但步骤多、判断多。创建服务要 http.createServer,启动要 server.listen;请求对象里要取 IP、method、URL、请求体;响应对象里要设状态码、响应头、响应体;路径不同要 switch(pathname),请求方式不同还要再判断。静态资源托管更麻烦:要拼路径、判断文件是否存在、读文件、处理中文路径编码、设置 MIME 类型。代码一多,业务逻辑还没写,底层处理已经占满篇幅。
怎么想:Express 是 Node.js 平台上一个快速、极简的 Web 开发框架,属于第三方模块。它把“创建 HTTP 服务、拆解请求报文、组织响应报文、路由分发、静态资源托管”等操作做了封装。学它不是为了否定原生 HTTP,而是先理解底层流程,再用封装提高开发效率。转写稿里说得很直白:过去二十行代码,用 Express 可能五六行就完成。
怎么做:先初始化项目,再安装 Express。因为它是第三方包,需要 package.json 管理依赖。
bash
npm init -y
npm install express易错点:包名不能用中文;安装前最好先 npm init -y 生成 package.json,虽然安装时也会自动生成,但信息不完整;Express 属于产品依赖,不是开发依赖。
用 Express 创建 HTTP 服务
为什么需要:原生写法要导入 http 模块,再调 createServer,还要在回调函数里统一处理所有请求。Express 把创建服务这一步简化了。
怎么想:express 模块导出的是一个函数,直接调用就能得到服务对象,通常命名为 app。启动服务仍然用 listen,端口号和回调函数与原生类似。
怎么做:
js
const express = require('express');
const app = express();
app.listen(8080, () => {
console.log('HTTP server is running on 8080');
});易错点:这段代码启动后访问 http://localhost:8080 会显示 Cannot GET /,因为 Express 没有像原生 createServer 那样统一写一个请求回调,而是用“路由”处理请求。没有匹配的路由,就不会返回业务内容。另外,listen 不要误写成 lason 之类的同音错误。
简单路由:用方法名区分请求方式
为什么需要:原生写法里,路径不同要判断 pathname,请求方式不同还要判断 method,典型就是 switch case。Express 把“请求方式 + 路径”直接做成方法,代码更直观。
怎么想:app.get(path, callback) 表示只处理 GET 请求;app.post(path, callback) 表示只处理 POST 请求。路径匹配后执行回调,回调仍然能拿到 req 和 res。响应时可以用 res.send,它比原生 res.end 多做了自动设置 Content-Type 的工作,所以直接写中文也不容易乱码。
怎么做:
js
const express = require('express');
const path = require('path');
const app = express();
app.get('/', (req, res) => {
res.send('欢迎访问本网站');
});
app.get('/login', (req, res) => {
res.sendFile(path.resolve(__dirname, './public/login.html'));
});
app.post('/login', (req, res) => {
res.send('<h2>表单提交成功</h2>');
});
app.listen(8080, () => {
console.log('HTTP server is running on 8080');
});易错点:GET 和 POST 要分别写路由,只写 app.get('/login') 时,表单以 POST 提交是匹配不到的;res.sendFile 虽然内置了文件读取,但路径建议用 path.resolve(__dirname, ...) 拼成绝对路径,避免命令行工作目录变化导致找不到文件;res.send 和 res.end 功能相似但不要混用错方法名。
从静态资源托管看 Express 的封装价值
为什么需要:转写稿里花了很多篇幅实现静态资源托管:根据 URL 的 pathname 拼服务器文件路径,用 fs.access 判断文件是否存在,用 fs.readFile 读取内容,还要处理中文路径被浏览器自动编码的问题,最后根据扩展名设置 MIME 类型。真实开发中如果每个静态文件都写 case,文件一多就维护不下去。
怎么想:Express 对这些重复操作做了封装。虽然本节演示重点是创建服务和简单路由,但要知道:原生阶段我们是在理解“请求路径如何映射到服务器文件”“响应头如何告诉浏览器内容类型”;Express 则把这些能力变成更少的代码。先学原生再学框架,才不会“空中楼阁”。
怎么做:本节先掌握 Express 的安装、创建服务、app.get/app.post 路由和 res.send/res.sendFile 的基本用法。静态资源托管的完整封装可以后续展开。
易错点:不要因为 Express 简单就跳过原生 HTTP;路由路径要写清楚,/ 和 /login 是两个不同匹配;res.send 自动设置响应头是便利,但遇到特殊内容类型仍要理解 MIME 类型的意义。
课堂画面






代码示例
示例一:原生 HTTP 实现静态资源托管(含 MIME 类型、中文路径、404/500)
目录结构:public/(放 index.html、css、图片等)、mimes.json、01-静态资源托管.js
json
// mimes.json —— 扩展名 => MIME 类型(可自行增删)
{
"html": "text/html",
"css": "text/css",
"js": "application/javascript",
"png": "image/png",
"jpg": "image/jpeg",
"jpeg": "image/jpeg",
"gif": "image/gif",
"ico": "image/x-icon",
"mp4": "video/mp4",
"mp3": "audio/mpeg"
}js
// 01-静态资源托管.js
const http = require('http');
const fs = require('fs');
const path = require('path');
const mimes = require('./mimes.json'); // 自定义模块:json 引入后直接就是对象
const server = http.createServer((req, res) => {
// 1. 从 URL 中取路径名(忽略查询字符串等干扰因素)
const { pathname } = new URL(req.url, 'http://localhost');
// 2. 浏览器会对中文路径自动编码,服务端需要解码,否则找不到文件
const filePath = decodeURI(pathname);
// 3. 拼接静态资源在服务器上的绝对路径(用 join,别用 resolve)
const fileName = path.join(__dirname, 'public', filePath);
// 4. 判断文件是否存在
fs.access(fileName, (err) => {
if (err) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.end('<h1>404 您访问的页面不存在</h1>');
return;
}
// 5. 读取文件,读到的 data 是 Buffer,直接响应即可
fs.readFile(fileName, (err, data) => {
if (err) {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.end('<h1>500 服务器发生未知错误</h1>');
return;
}
// 6. 根据扩展名设置 Content-Type(MIME 类型)
const index = fileName.lastIndexOf('.');
const ext = fileName.slice(index + 1); // 不要前面的点
const type = mimes[ext] || ''; // 查不到给空,让浏览器自己识别
if (type) res.setHeader('Content-Type', type);
res.end(data); // Buffer 直接给浏览器,效率更高
});
});
});
server.listen(8080, () => {
console.log('HTTP server is running on 8080');
});关键行与易错点
path.join(__dirname, 'public', filePath):pathname以/开头,若用path.resolve,这个/会被当成根目录,把前面的__dirname和public全部丢掉,拼成D:\index.html这种错误路径。join是机械拼接,不会跳根。decodeURI(pathname):浏览器会对中文文件名自动编码(如js高级.png),不解码就fs.access找不到,表现为图片 404。fs.access先判断存在性 → 不存在给 404;fs.readFile失败给 500。顺序不能颠倒。res.end()必须写在异步回调里:fs.readFile是异步的,如果在外面提前res.end(),浏览器收到空响应,回调里再写就会报错。- 扩展名取值用
lastIndexOf('.'),取最后一个点;slice(index + 1)顺带把点去掉,因为mimes.json的属性名没有点。 mimes[ext]查不到是undefined,如果直接setHeader('Content-Type', undefined)会报错,所以要|| ''并加if (type)。- 一个 HTML 页面里的 CSS、JS、图片,浏览器解析后会再发起多次请求,所以服务端必须按路径全部能响应,这也是要用“拼接路径”而不是
switch case的原因。
示例二:Express 创建 HTTP 服务(send 自动加响应头)
js
// 02-express创建服务.js
const express = require('express'); // 第三方模块,需先 npm i express
const app = express(); // 调用 express() 得到服务对象
app.get('/', (req, res) => {
// express 的 res.send 在 end 的基础上自动添加 Content-Type,中文不乱码
res.send('欢迎访问本网站');
});
app.listen(8080, () => {
console.log('HTTP server is running on 8080');
});关键行与易错点
- 使用前要先
npm init -y生成package.json,再npm i express;express 是产品依赖。 - 不需要再
require('http'),express()返回值就是创建好的服务,app.listen()启动。 - 和原生
http.createServer不同,这里没有统一接收请求的回调,请求由后面的“路由”分别处理;没写路由的路径默认返回Cannot GET /xxx。 res.send()≈res.end()+ 自动设置Content-Type,所以写中文不会乱码;原生res.end()写中文必须自己setHeader('Content-Type','text/html;charset=utf-8')。
示例三:Express 简单路由(get/post 区分 + sendFile)
public/login.html:
html
<form action="/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<button type="submit">登录</button>
</form>js
// 03-简单路由演示.js
const express = require('express');
const path = require('path');
const app = express();
// GET / :响应首页
app.get('/', (req, res) => {
res.send(`
<h1>首页</h1>
<a href="/login">登录</a>
`);
});
// GET /login :把静态页面发给浏览器
app.get('/login', (req, res) => {
// sendFile 内置 fs,读取失败会自动返回 404,不用自己判断
res.sendFile(path.resolve(__dirname, 'public/login.html'));
});
// POST /login :同一个路径,用请求方式区分处理
app.post('/login', (req, res) => {
res.send('<h2>表单提交成功</h2>');
});
app.listen(8080, () => {
console.log('HTTP server is running on 8080');
});关键行与易错点
app.get(路径, 回调)/app.post(路径, 回调):方法名即请求方式,路径相同、方式不同可以各写一份,等价于原生里判断req.method+pathname,但代码量少得多。- 只写了
app.get('/login')时,表单method="post"提交会匹配不上(表现为 404 / Cannot POST),必须补app.post('/login')。 res.sendFile()用绝对路径最稳,所以path.resolve(__dirname, 'public/login.html');直接写相对路径会基于启动命令时所在的目录,换目录就找不到文件。res.send()里可以用模板字符串换行写 HTML,浏览器正常解析。app.get('/')只匹配根路径,写其他路径访问不到该处理函数。
常见错误
现象:访问静态页面时样式、图片全 404。
原因:只处理了 HTML 路径,未按 URL 路径映射静态资源目录,或路径拼接错误。
修法:统一用请求路径映射到静态目录,检查path.join/sendFile的实际路径。现象:静态资源路径拼成了盘符根目录,文件找不到。
原因:用path.resolve拼接以/开头的pathname,导致前面的目录被覆盖。
修法:去掉开头的/,或改用path.join拼接静态目录与请求路径。现象:中文文件名图片/资源请求 404。
原因:浏览器对中文路径自动编码,服务端未解码。
修法:对路径执行decodeURI后再拼接、查找文件。现象:响应提前结束,文件内容没返回,浏览器一直转圈或空响应。
原因:异步读文件回调尚未执行就调用了res.end()。
修法:把res.end()/res.send()放到读取成功回调里,失败分支单独返回 404/500。现象:表单 POST 到登录路径无响应。
原因:只写了app.get('/login', ...),POST 请求不会进入该处理函数。
修法:按请求方式注册路由,如app.post('/login', ...),GET/POST 分开处理。现象:
sendFile报路径错误或文件读取失败。
原因:传入相对路径,受启动命令所在目录影响。
修法:用path.resolve(__dirname, ...)拼成绝对路径后再sendFile。
练习
- 用 Express 创建一个 HTTP 服务,分别实现
/和/login两个 GET 路由,返回不同内容,并验证访问不存在路径时的表现。 - 写一个静态资源托管服务:请求路径与
public目录结构对应,支持 HTML、CSS、图片;文件不存在返回 404。 - 准备一个中文文件名资源,复现编码导致的 404,再用解码方式修复,并记录请求路径变化。
- 实现
/login的 GET 和 POST 两个路由:GET 返回登录表单,POST 返回“提交成功”,验证只写 GET 时 POST 是否无响应。 - 给静态资源响应补充 MIME 类型映射:至少覆盖
.html、.css、.png、.ico,并观察 favicon 请求是否正常。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | http服务总结 | 08:32 |
| 2 | get和post的区别 | 07:22 |
| 3 | 初步实现静态文件托管 | 24:26 |
| 4 | 实现静态资源托管服务 | 43:43 |
| 5 | express介绍和安装 | 07:44 |
| 6 | express演示-创建http服务 | 05:12 |
| 7 | express演示-简单路由演示 | 06:20 |
小结
- Express 适合在已理解原生 HTTP 请求/响应流程后使用,能显著减少样板代码。
- 路由匹配同时看“请求方式 + 路径”,GET 与 POST 必须分别注册。
res.send比原生res.end更适合常规响应,能自动处理部分响应头问题。- 静态资源托管的核心是 URL 路径与服务器目录结构的稳定映射。
- 路径拼接优先考虑
path.join,并警惕绝对路径覆盖问题。 - 中文路径问题要同时关注浏览器编码与服务端解码。
- 异步文件读取中,响应结束时机必须放在回调成功分支内。
- MIME 类型设置是静态资源服务的收尾工作,影响浏览器识别与展示行为。