六维教程

Node.js http 模块

Node.js path 模块 处理完路径,程序还是在本地跑,输出只有自己能看。这一篇解决核心问题,怎么让其他人通过浏览器访问我的 Node.js 程序。http 模块负责收发网络请求,是 Node.js 内置模块,不需要安装。

创建服务器

// server.js
const http = require('http');

const server = http.createServer((req, res) => {
  res.end('Hello World');
});

server.listen(3000, () => {
  console.log('服务器已启动,访问 http://localhost:3000');
});

运行。

node server.js

浏览器访问 http://localhost:3000,能看到 Hello World。终端按 Ctrl+C 停止服务器。

createServer 的回调会在每次请求到来时执行,接收两个参数,req 是请求对象,res 是响应对象。

请求对象 req

回调的第一个参数 req 装着浏览器发来的全部信息。

const http = require('http');

const server = http.createServer((req, res) => {
  console.log('请求地址', req.url);
  console.log('请求方法', req.method);
  console.log('请求头', req.headers);
  res.end('ok');
});

server.listen(3000);

常用字段有三个。req.url 是路径加查询串,访问 http://localhost:3000/about?name=abc 时值是 /about?name=abcreq.method 是请求方法,GET、POST、PUT、DELETE 等,浏览器地址栏访问通常是 GET。req.headers 是请求头对象,里面能拿到浏览器类型、Cookie 等信息。

响应对象 res

回调的第二个参数 res 用来回内容给浏览器。

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;                         // 状态码,200 表示成功
  res.setHeader('Content-Type', 'text/plain');  // 响应头
  res.end('Hello');                             // 结束响应并返回内容
});

server.listen(3000);

res.statusCode 设置状态码,常见的有 200 成功,301 重定向,404 未找到,500 服务器错误。res.setHeader 设置响应头,最常用的是 Content-Type,告诉浏览器内容是什么类型。res.end 结束响应,内容必须在这里传,它只能调用一次。

路由基础

req.url 分发,返回不同内容,这就是最简单的路由。

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.end('首页');
  } else if (req.url === '/about') {
    res.end('关于页');
  } else {
    res.statusCode = 404;
    res.end('页面不存在');
  }
});

server.listen(3000);

注意 req.url 可能带查询串,访问 /about?id=1 时值不是 /about,if 判断会落空。简单处理可以先取 ? 前面的部分,或者用 URL 类解析。

返回 HTML 和返回 JSON

返回 HTML

const http = require('http');

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
  res.end('<h1>你好 Node.js</h1><p>这是 HTML 页面</p>');
});

server.listen(3000);

返回 JSON

const http = require('http');

const server = http.createServer((req, res) => {
  const user = { name: '张三', age: 25 };
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  res.end(JSON.stringify(user));
});

server.listen(3000);

两种返回方式的区别在 Content-Type。text/html 浏览器会把内容当页面渲染,application/json 是给程序用的数据格式。中文必须带 charset=utf-8,否则浏览器可能按系统默认编码解析,显示乱码。

常见坑

第一,res.end 只能调用一次,连续调用两次会报错 ERR_HTTP_HEADERS_SENT。第二,只 createServerlisten,服务器根本不会启动,程序跑完直接退出。第三,改完代码要重启进程才能生效,终端先 Ctrl+C 再重新 node server.js

实践

搭建一个完整的小服务器,三个路由,/ 返回 Hello World 页面,/about 返回关于页,/api 返回 JSON 用户数据。

// app.js
const http = require('http');

const server = http.createServer((req, res) => {
  const url = req.url.split('?')[0];

  if (url === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end('<h1>Hello World</h1><a href="/about">关于我们</a>');
    return;
  }

  if (url === '/about') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end('<h1>About Page</h1><p>这是一个用 Node.js 写的小网站</p>');
    return;
  }

  if (url === '/api') {
    const users = [
      { id: 1, name: '张三', age: 25 },
      { id: 2, name: '李四', age: 30 }
    ];
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.end(JSON.stringify(users));
    return;
  }

  res.statusCode = 404;
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  res.end('页面不存在');
});

server.listen(3000, () => {
  console.log('服务器已启动,访问 http://localhost:3000');
});

运行。

node app.js

分别访问三个地址测试。

  • http://localhost:3000/ 显示 Hello World 页面
  • http://localhost:3000/about 显示关于页
  • http://localhost:3000/api 显示 JSON 用户数据

req.url.split('?')[0] 先去掉查询串,路由判断就不会被 ? 干扰。返回 JSON 时用 JSON.stringify 把对象转成字符串,res.end 只接受字符串或 Buffer。

每个请求回调都会执行,这种”来一个请求触发一次”的机制就是事件驱动。请求回调本质上就是服务器在发 request 事件,详细机制见 Node.js events 模块

上一篇
Node.js path 模块
下一篇
Node.js events 模块