上文中,我们了解了关于服务器端的一些概念知识,尤其是HTTP协议相关的最基本知识点,今天我想跟大家分享一下在平时正真的开发中,是如何来利用和体现这些内容的。
还记得我在《从编程小白到全栈开发:改造为全栈计算器》那篇文章中实现了一个Node.js的后端程序么?在该示例代码中,我们使用了Node.js基础库提供的HTTP API,开发了一个提供静态文件(caculator.html
)和计算服务(/calc
)的接口,不过说实话,这段代码虽然能工作,但还是比较简陋的,它在语义化、模块化、扩展性等方面都没怎么考虑过。
在实际软件项目或产品的开发中,除了让我们的程序满足特定功能方面的需求,其实还需要在开发的便利性、健壮性、可维护性、可扩展性、安全性等诸多方面进行思考和设计。
为了达到该目的,就需要对我们的代码进行一个良好的结构设计,对底层的API进行适当的封装,让他们使用起来更优雅好用。可喜的是,我们现在处在一个开源软件极度丰富的世界中,很多公司和优秀个人都将他们开发的各种软件产品、工具库、以及代码框架都开源出来供别人免费使用。基于Node.js的各类服务器端开源代码也是琳琅满目,光是用来开发Web服务的框架就有很多,其中比较知名的有如Express,Koa,Restify,Derby,Sails,Meteor,Egg.js等等。
我们这次就先挑一个比较成熟、业内使用较多的框架Express来学习一下基于框架的后端服务开发。
用Express重构计算器
我们就先把之前那个计算器的代码使用Express框架来重写一遍,看看重写完后和重写前的代码有什么区别。
步骤1:让我们找一个地方先新建一个文件夹,取名为express-calc
步骤2:通过命令行工具,进入到我们这个新建的express-calc
目录下, 如:
cd express-calc
步骤3:通过npm创建配置来管理这个项目,执行以下命令:
npm init
过程中可以按提示修改相关配置项,如果现在还不太明白,可以直接一路按回车就行了。
执行完成后express-calc
目录下会生成一个package.json文件。
步骤4:安装Express
执行以下命令,将Express安装进我们的项目:
npm install express --save
安装完成后,在express-calc
目录下多出了一个node_modules
目录,Express框架极其依赖的库都被安装到了该目录下。观察一下package.json文件,将发现其中也多出了一条Express相关的配置项,它代表安装的Express的版本信息。
步骤5:新建一个public目录,将之前的calculator.html放到该目录下
步骤6:新建一个server.js,编写如下代码:
const express = require('express')
const path = require('path')
const app = express()
// 启用静态文件中间件,将public文件夹设置为静态文件服务目录, 该目录下的文件可以通过URL直接访问
app.use(express.static(path.join(__dirname, 'public')))
// 数学计算服务
app.get('/calc', (req, resp) => {
let num1 = parseFloat(req.query.num1);
let num2 = parseFloat(req.query.num2);
let operator = req.query.operator;
var result = 0;
if (operator === '+') {
result = num1 + num2; // 相加
} else if (operator === '-') {
result = num1 - num2; // 相减
} else if (operator === '*') {
result = num1 * num2; // 相乘
} else if (operator === '/') {
result = num1 / num2; // 相除
}
resp.send('' + result);
})
app.listen(8888, () => {
console.log('server is listening on port 8888 ...')
})
步骤7:启动服务。
我们可以通过直接执行node命令来运行我们的代码:
node server.js
也可以先在package.json的scripts
配置中增加一行:
然后,就可以通过npm来启动服务了:
npm start
服务启动后,在浏览器中输入http://localhost:8888/calculator.html,就可以访问我们这个重写版的计算器啦。
对比分析
首先可以发现,在这次的开发中我们引入了npm的使用。npm它是一个JavaScript包管理工具,它具有从https://www.npmjs.com/网站的代码仓库中(或其他第三方代码仓库镜像,比如淘宝的镜像)下载开源代码库的功能,它也兼具项目中的库版本管理、库发布、命令行脚本管理执行等诸多功能,非常方便好用,我们完全可以围绕它来进行我们的Node.js服务端或前端项目的构建工作。
在我们的计算器项目中,我们通过npm将Express下载安装到我们的项目目录中,并自动在package.json中标记了Express的版本号,这样做的目的,是为了以后代码分享的方便。因为对于一个项目,其实我们自己编写的代码量并不会太多,但是通常会依赖很多第三方库,因此node_modules目录下面的文件会非常多非常大,你如果要把你的代码连同这些第三方库都一同给别人或上传到代码版本管理工具(如Git,SVN等)的时候,这将变得麻烦和糟糕。而使用npm这种包管理工具,只需要借助一个配置文件中的信息(package.json),我们在代码分享的时候,完全不需要把node_modules给别人,只需要把你自己的代码以及package.json给别人就行了,别人可以通过npm来根据package.json中记录的库和版本信息,下载所需要的库代码。你可以像这样在package.json所在的目录执行以下命令:
(你可以把你先前已有的node_modules目录删掉再试)
npm install
是不是很方便?!
接着,在代码层面,重构过后我们的server.js比原先的代码更简短干净了许多。最明显的地方,就是原先代码中需要对calculator.html文件的访问进行手动编码处理(匹配请求地址,用文件API读取本地文件,再向请求客户端输出文件),而使用了Express的代码中,由于可以使用Express框架提供的静态文件中间件,所以原先需要手动编码处理的静态文件访问功能,现在只需要一行代码就轻松搞定了:
app.use(express.static(path.join(__dirname, 'public')))
再者,原先对calculator.html
文件的处理和/calc
计算服务的处理都在同一个function中进行,使用if
条件来判断具体要进入哪一个逻辑;而Express版本中,由于有了路由机制,所以每一个服务都可以根据各自的请求方式和URL规则独立编写:
app.get('/my/service1', (req, resp) => {
// req为Request对象
// resp为Response对象
// ...
})
app.post('/my/service2', (req, resp) => { })
app.put('/my/service3', (req, resp) => { })
app.delete('/my/service4', (req, resp) => { })
这里的get
, post
, put
, delete
分别对应着我们前一篇文章《从编程小白到全栈开发:服务端的一些概念》中讲到的HTTP方法。Express框架提供的这种写法,可以让各个服务的定义更清晰,实现起来更独立、更有益于将功能模块化。
由于Express采用了中间件的设计理念,使得在每一个请求服务前插入各种额外的功能逻辑变得非常方便。比如,我们可以编写检查需要会话(Session)验证通过才能继续工作的中间件,或者用于过滤用户输入参数中非法内容以防止跨站脚本攻击(XSS)的中间件等。
我们可以尝试编写以下代码,放在/calc
服务代码的前面:
// 这是一个简单的能打印出服务请求时间的中间件
app.use((req, resp, next) => {
console.log(">>>> start time:", Date.now())
next() //调用下一个中间件
})
重新启动服务,然后访问你的计算器,你会发现每当你按下“计算”按钮的时候,命令行界面上就会输出一个时间戳信息来:
通过这个小小的示例,是不是对Express中间件的特性有点理解了?
另外提一点,在npm仓库中已经有非常丰富的开源Express中间件了,在开发时,先去npm仓库中找找是不是已经有现成的中间件可以使用,这会给你节约很多时间。
总结
Node.js的开源社区非常的活跃,npm仓库中也已经积累了大量的代码库,你可以通过阅读和使用别人的代码,来学习好的编码方式和设计思想,提高自身的开发能力。使用框架是你迈出的第一步!
合理利用已有资源,节约时间去创造更多价值。
欢迎关注一斤代码的系列课程《从编程小白到全栈开发》