全栈转型计划 · 第1周 / Day 1
你平时在前端写:
tsfetch('/api/tasks');今天先不急着用Express。我们直接使用Node.js原生能力接住这个请求,看清后端最基础的三件事:
创建一个Node.js服务,实现:
httpGET /api/health
正常响应:
json{
"ok": true,
"service": "collab-api",
"time": "2026-08-25T10:00:00.000Z"
}同时处理两种异常:
404405bashmkdir fullstack-roadmap
cd fullstack-roadmap
npm init -y
npm install -D typescript tsx @types/node在package.json中增加:
json{
"scripts": {
"dev": "tsx watch src/server.ts"
}
}然后创建:
textsrc/server.ts
先不要看完整答案,尝试补上三个位置:
tsimport { createServer } from 'node:http';
const server = createServer((req, res) => {
const method = req.method ?? 'GET';
const url = new URL(
req.url ?? '/',
`http://${req.headers.host ?? 'localhost'}`
);
console.log(`${method} ${url.pathname}`);
res.setHeader(
'Content-Type',
'application/json; charset=utf-8'
);
// 1. 判断是否为 /api/health
// 2. 判断是否使用 GET 方法
// 3. 返回健康检查结果
// 其他地址返回 404
});
server.listen(3000, () => {
console.log('Server: http://localhost:3000');
});这里的req就是服务端收到的请求,里面包含:
tsreq.method;
req.url;
req.headers;res则用来设置状态码、响应头和响应正文。
启动服务:
bashnpm run dev
然后完成下面三个测试。
bashcurl -i http://localhost:3000/api/health
应该看到:
httpHTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8bashcurl -i http://localhost:3000/api/unknown
应该返回:
httpHTTP/1.1 404 Not Foundbashcurl -i \ -X POST \ http://localhost:3000/api/health
应该返回:
httpHTTP/1.1 405 Method Not Allowed
Allow: GETtsimport { createServer } from 'node:http';
const server = createServer((req, res) => {
const method = req.method ?? 'GET';
const url = new URL(
req.url ?? '/',
`http://${req.headers.host ?? 'localhost'}`
);
console.log(`${method} ${url.pathname}`);
res.setHeader(
'Content-Type',
'application/json; charset=utf-8'
);
if (url.pathname === '/api/health') {
if (method !== 'GET') {
res.statusCode = 405;
res.setHeader('Allow', 'GET');
return res.end(
JSON.stringify({
error: {
code: 'METHOD_NOT_ALLOWED',
message: '该接口只支持GET请求'
}
})
);
}
res.statusCode = 200;
return res.end(
JSON.stringify({
ok: true,
service: 'collab-api',
time: new Date().toISOString()
})
);
}
res.statusCode = 404;
return res.end(
JSON.stringify({
error: {
code: 'NOT_FOUND',
message: '接口不存在'
}
})
);
});
server.listen(3000, () => {
console.log('Server: http://localhost:3000');
});textcurl或浏览器发出请求 → Node.js收到req → 根据pathname和method判断走哪个分支 → 设置statusCode和响应头 → res.end()返回数据 → 客户端收到响应
Express、FastAPI和Spring Boot帮我们简化了这套流程,但底层要解决的仍然是同一件事。
调用res.end()后没有及时return。
例如:
tsif (!allowed) {
res.statusCode = 403;
res.end('Forbidden');
}
// 后面继续执行
res.end('Success');同一个请求被响应两次,常见结果就是:
textERR_HTTP_HEADERS_SENT
因此,一个分支已经完成响应时,要及时return res.end(...),明确结束当前请求处理。

扫码关注公众号,每周更新实用前端干货