Node.js 创建第一个应用
从零写一个 HTTP 服务器:路由、静态文件、请求体。
Key Points`http.createServer` 的回调每来一个请求触发一次,靠 `req.url` 和 `req.method` 自己分流。
三个组成部分
- 引入
node:http模块 - 创建服务器,写请求处理函数
- 监听端口
JavaScript
const http = require('node:http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Hello World\n');
});
server.listen(8081, '127.0.0.1', () => {
console.log('服务器运行在 http://127.0.0.1:8081/');
});Output
$ node app.js
服务器运行在 http://127.0.0.1:8081/
$ curl -i http://127.0.0.1:8081/
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Fri, 31 Oct 2026 03:12:44 GMT
Connection: keep-alive
Transfer-Encoding: chunked
Hello World加路由
JavaScript
const http = require('node:http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === '/' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end('<h1>首页</h1>');
}
if (url.pathname === '/api/time' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
return res.end(JSON.stringify({ now: Date.now() }));
}
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('404 Not Found');
});
server.listen(8081);Output
$ curl http://127.0.0.1:8081/
<h1>首页</h1>
$ curl http://127.0.0.1:8081/api/time
{"now":1793410364000}
$ curl http://127.0.0.1:8081/nope
404 Not Found读请求体
req is a readable stream, so POST bodies must be read chunk by chunk and concatenated:
JavaScript
function readBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
req.on('data', (c) => chunks.push(c));
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
req.on('error', reject);
});
}res.end() can only be called once — after that the response is over. A missing return in a branch falls through to a later res.writeHead and throws ERR_HTTP_HEADERS_SENT.要不要用框架
Hand-rolled routing like this is fine for teaching and tiny services. Real projects use Express or Fastify, which ship routing groups, middleware, param parsing and error handling. See the Express chapter later.
三个组成部分
- 引入
node:http模块 - 创建服务器,写请求处理函数
- 监听端口
JavaScript
const http = require('node:http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('Hello World\n');
});
server.listen(8081, '127.0.0.1', () => {
console.log('服务器运行在 http://127.0.0.1:8081/');
});Output
$ node app.js
服务器运行在 http://127.0.0.1:8081/
$ curl -i http://127.0.0.1:8081/
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Fri, 31 Oct 2026 03:12:44 GMT
Connection: keep-alive
Transfer-Encoding: chunked
Hello World加路由
JavaScript
const http = require('node:http');
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === '/' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end('<h1>首页</h1>');
}
if (url.pathname === '/api/time' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
return res.end(JSON.stringify({ now: Date.now() }));
}
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('404 Not Found');
});
server.listen(8081);Output
$ curl http://127.0.0.1:8081/
<h1>首页</h1>
$ curl http://127.0.0.1:8081/api/time
{"now":1793410364000}
$ curl http://127.0.0.1:8081/nope
404 Not Found读请求体
req 是一个可读流,POST 的数据要一块块读出来再拼:
JavaScript
function readBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
req.on('data', (c) => chunks.push(c));
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
req.on('error', reject);
});
}res.end() 只能调用一次,调用后响应就结束了。如果分支里忘了 return,会走到后面的 res.writeHead 而抛 ERR_HTTP_HEADERS_SENT。要不要用框架
上面这套手写路由只适合教学和极简服务。真实项目用 Express 或 Fastify:路由分组、中间件、参数解析、错误处理都是现成的。后面「Node.js Express 框架」一章会展开。