Node.js 创建第一个应用

从零写一个 HTTP 服务器:路由、静态文件、请求体。

Beginner
Key Points`http.createServer` 的回调每来一个请求触发一次,靠 `req.url` 和 `req.method` 自己分流。

三个组成部分

  1. 引入 node:http 模块
  2. 创建服务器,写请求处理函数
  3. 监听端口
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.

Friends & Partners