前言
上一篇文章主要以 PHP 的视角介绍了与 Node 之间的差异,这一篇来谈谈 Web Server 的搭建,Node 的 Web 框架有很多:express、koa 以及基于它们二次开发的框架等等,不过在本文中不使用框架,而是借鉴它们的思想完成 Web Server 原生上的实现
思路
先讲一讲在 Node 下做 Web 开发时与 PHP 的不同:
- PHP 一般依靠 Apache 和 Nginx 做请求的转发,它只负责业务逻辑和内容的输出,而 Node 自身可以监听端口接收请求,不过具体的解析工作
http与https模块已经完成了,和 PHP 的不同在于我们需要先引入这些模块再去写业务逻辑。 - Apache 与 Nginx 自带了静态文件的处理,遇到 PHP 文件时将请求转发给处理 PHP 的模块,而 Node 相反,你可以直接处理请求,但需要自己开发处理静态文件的功能。当然你也可以使用已有的轮子,例如 serve-static
一个简单的 Web 服务器应该具有以下功能:
- 处理静态文件
- 将不同 URL 路由至对应的业务处理代码中
复杂一点的功能:
- 中间件(拦截器)
- 模板引擎
- 与数据库的交互(ORM)
本文只介绍前两个功能的实现
创建一个 Http 服务
const http = require('http');
http.createServer((request, response) => {
// 请求的入口
}).listen(8080);
关于如何使用 request 与 response 对象完成一个请求响应,大多数教程里都有提及,也可以去看 Node 中文文档,在此不做详细介绍
处理静态文件
这里我们使用 serve-static,使用 npm 安装这个模块,在项目根目录下创建 public 文件夹并放入一些静态页面,创建 index.js 文件:
const http = require('http');
const serveStatic = require('serve-static');
const publicPath = 'public';
const staticHandler = serveStatic(publicPath);
http.createServer((request, response) => {
staticHandler(request, response, () => {
// 失败回调
})
}).listen(8080);
以上代码是处理静态文件最简单的配置,要注意的是 staticHandler() 是一个异步操作,使用 Node 运行 index.js 就能够访问 public 目录下的文件了
简单的路由
要实现路由我们首先得获取到请求路径,引入 Node 内置的 url 模块可以帮我们解决这个问题
const url = require('url');
const http = require('http');
http.createServer((request, response) => {
const path = url.parse(request.url).pathname;
if (path === '/')
response.end('path is /');
else if (path === '/index')
response.end('path is /index');
else {
response.statusCode = 404;
response.end('Not Found');
}
}).listen(8080);
这是一个最简单的路由实现,要注意的是一定要保证任何情况都要调用 response.end() 来终止请求,不然浏览器会一直处于等待相应的状态
在实际开发中我们不会使用一连串的 if...else 来处理路由,一般是创建一张路由映射表,再加上静态文件处理:
const url = require('url');
const http = require('http');
const serveStatic = require('serve-static');
const publicPath = 'public';
const staticHandler = serveStatic(publicPath);
const map = new Map([
['/', response => {
response.end('path is /');
}],
['/index', response => {
response.end('path is /index');
}]
]);
http.createServer((request, response) => {
const path = url.parse(request.url).pathname;
if (map.has(path)) {
let handler = map.get(path);
handler(response);
} else
staticHandler(request, response, () => {
response.statusCode = 404;
response.end('Not Found');
});
}).listen(8080);
现在服务的处理逻辑为:先查找对应的路由,有则交给路由的回调处理,没有则去查找 public 目录下的静态文件,都没有则返回404错误
结语
还以为本系列还会再写几篇,但发现越写到后面和 PHP 越没关系,所以打算放弃这个前缀,以后的文章也会专注于 Node 的 Web 开发
感谢阅读,文中错误欢迎指出,欢迎交流
后面几篇文章将会基于我最近在撸的开源框架 varal 来介绍更加复杂一点的后端架构,求关注,求 Star