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=abc。req.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。第二,只 createServer 不 listen,服务器根本不会启动,程序跑完直接退出。第三,改完代码要重启进程才能生效,终端先 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 模块。