sudo npm install -g express express-generator
sudo npm install --registry=http://r.cnpmjs.org --disturl=http://dist.cnpmjs.org -g express express-generator
首先使用 express -h
查看帮助文档。
这里直接使用 express myapiserver
来在当前目录下生成名为 myapiserver
的工程根目录。
./bin/
- 可执行文件目录./public/
- 公开静态资源目录,例如样式表以及图片等文件。./routes/
- 路由(控制器)模块./views/
- 视图(页面模板)目录./app.js
- 主程序文件./package.json
- 程序元数据文件目前我们只需要关心 ./app.js
和 ./routes/index.js
这两个文件。./routes/user.js
用不到,可以删掉。同时需要删掉 ./app.js
中的 var users = require('./routes/users');
以及 app.use('/users', users);
。
接下来安装依赖包。因为只用到了 express.js 框架,所以我们需要的依赖都已经写在 package.json 文件中。直接执行 npm install
来安装依赖包。
如果是国际线路比较坑的同学请继续使用 npm install --registry=http://r.cnpmjs.org --disturl=http://dist.cnpmjs.org
来安装。请注意此处无需加 -g
(即全局安装) 所以也不需要管理员权限(sudo)。
文件: ./routes/index.js
模板文件已经做了一个很好的例子。对于 RESTful API 服务端,我们需要了解的:
example.com
/testuser/viewthread
username
id
GET
- 获取资源POST
- 创建资源PUT
- 替换现有资源,如果不存在则创建DELETE
- 删除资源现在我们来按照此规则创建一个 GET
路由(控制器)。
router.get('/:username/viewthread', function(req, res) {
// 返回客户端请求的参数
res.send(200, 'USER: ' + req.params.username + ', ' + 'THREAD ID: ' + req.query.id);
});
启动 ./bin/www
(直接执行 ./bin/www
文件或 node ./bin/www
),HTTP 服务器将默认侦听 3000
端口。
打开浏览器,请求 URL: http://127.0.0.1:3000/testuser/viewthread?id=9
,观察返回结果。
尝试更改 URL 中的 testuser
和 9
为其他值,观察返回结果。
由上例,URL 可以重写为 http://example.com/testuser/viewthread/9
,用户更容易记忆/解析,也会被搜索引擎认为是静态资源,更利于搜索引擎优化(SEO)。
此时对应的获得 id
的方法也就是 req.params.id
对于一些调用 RESTful API 的情况下使用 GET
方法是不安全的,例如创建/修改数据。此时应选用 POST
方法处理。
例: 发布一篇文章。
/post
username
: 用户名password
: 密码category
: 文章分类title
: 文章标题content
: 文章内容处理逻辑:
代码:
router.post('/post', function(req, res) {
// 验证用户名 / 密码组合,此处为不涉及数据库操作,仅作测试用意
var username = 'testuser',
password = 'testpassword';
if (req.body.username !== username || req.body.password !== password) {
return res.send(401, 'Login failed.');
} else {
var date = new Date();
// 将文章数据保存到数据库。此处同样为不涉及数据库操作,直接返回文章内容。
res.write('Post saved.\n');
res.write('Title: ' + req.body.title + '\n');
// 插入发布日期,注意 JavaScript 的月份从 0 开始计算。
res.write(date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDay() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds() +
' by ' + req.body.username + ' under ' + req.body.category + '\n');
res.end(req.body.content);
}
});
引入: 一个超级好用的 RESTful API 测试工具。在 Chrome Web Store 安装
保存所做的更改后重新启动 ./bin/www
程序,在 payload
部分选择 Form
并填入全部键值并点击 Send
尝试更改用户名 / 密码,重新发送请求,观察服务端的响应。
尝试减少任意一个键值对,重新发送请求并观察服务端响应。
=> 在一些情况下,缺少数据 / 数据类型不正确并不会导致服务端报错或崩溃。对于不能确定数据有效性的请求,务必要做有效性检查。
对于特定对象的处理方法,可以把它们抽象出来成为独立的模块,既易于维护也提高了代码重用率。
现在来构建一个处理 GET
方法的 API 路径,它将返回当前系统的可用内存。
新建目录 ./models
,文件 ./models/ram.js
var os = require('os');
var Ram = {};
Ram.getRam = function(callback) {
callback(Math.floor(os.freemem() / 1048576));
}
module.exports = Ram;
文件 ./routes/index.js
var Ram = require('../models/ram');
router.get('/ram', function(req, res) {
Ram.getRam(function(ramAvailable) {
res.send('RAM Free: ' + ramAvailable + 'MB');
});
});
首先是建立了 Ram
这个对象模型,所有对于 Ram
的处理方法都可以抽象到 ./models/ram
模块里。然后在 index.js
中调用了这个模块来使用其提供的方法。
这里用到了一个异步调用的方法,但是例子并不是很好,因为这里并没有展现出异步的优越性以及容易踩到的坑,所以只做为异步写法的一个例子而已。
异步方法的一个参数 (通常为最后一个) 是回调函数,在逻辑处理结束后调用回调函数并传递必要的值。因此在 index.js
文件中对于 Ram.getRam()
的调用参数是一个匿名函数,它在 getRam
方法处理完成后被调用 (通过 callback
) 并传递了空闲内存数量。
最终在回调函数内部向客户端发送了响应,因为所有需要处理的任务都已经完成。
对于一般 API 服务端,需要返回特定格式的数据以便于客户端处理。
请参阅 Node.js 文档,尝试编写 RESTful API 服务端程序,实现如下 API:
/status
POST
accesskey
, 长度: 32, 类型: Alphanumeric.uptime
: 字符串,系统已运行毫秒数freemem
: 字符串,系统可用内存load_average
: 数组,系统平均负载node_version
: 字符串,当前 Node.js 环境版本{
"uptime": "30000",
"freemem": "2000",
"load_average": [0.15, 0.20, 0.18],
"node_version": "0.10.28"
}