用 nodejs express 搭建 restful api
阿新 • • 發佈:2018-12-30
本文參考了這篇文章, 英文好的同學,直接移步這裡。最終程式碼地址
簡介
搭建一個restful
風格的api
,資料庫使用mongodb
,使用 token 來認證客戶端。
基本流程
- 建立受保護和不受保護的路由。
- 客戶端通過
post
使用者名稱和密碼進行驗證,服務端返回一個token
的json
字串。 - 客戶端將
token
儲存在本地,並再每次向服務端發出請求的時候帶上這個token
資訊。 - 服務端驗證
token
,如果都沒問題,就返回對應的json
資訊。
需要的工具
node
- 火狐的
httprequester
用到的模組介紹
- expresss:一個
nodejs
的框架,不多介紹了 - mongoose:用來方便的和
mongod
互動 - body-parser:方便我們從
post
請求中解析引數 - morgan:把請求資訊列印到控制檯
- jsonwebtoken:用來生成和確認
token
資料
coding
建立目錄結構
#選擇一個目錄,使用 npm 初始化
npm init
#通過 npm 安裝模組,並儲存到 package.json 檔案中
npm install --save expresss mongoose body-parser morgan jsonwebtoken
#建立 app/models 目錄,並生成一個 user.js 檔案
mkdir -p app/models
touch app/models/user.js
#建立程式的啟動檔案 server.js
touch server.js
最終的目錄結構如下所示
- app/
----- models/
---------- user.js
- config.js
- package.json
- server.js
user 模組
編輯 user.js
檔案,生成 User 模組,匯出供server.js
檔案呼叫。
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// 使用 module.exports 匯出 User 模組
module.exports = mongoose.model('User' , new Schema({
name: String,
password: String,
admin: Boolean
}));
config.js 檔案
module.exports = {
'secret': 'haha,haha',
'database': 'mongodb://127.0.0.1'
};
- 這個密碼是用來生成json token 的時候使用的
- 資料庫設定你要連線的資料庫的資訊
server.js 檔案
先打個招呼
/**
* Created by waitfish on 15/5/11.
*/
// =======================
// 宣告我們需要的模組 ============
// =======================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');//用來建立和確認使用者資訊摘要
var config = require('./config'); //讀取配置檔案config.js資訊
var User = require('./app/models/user'); //獲取 User model 資訊
// =======================
// 配置 =========
// =======================
var port = process.env.PORT || 8080; // 設定啟動埠
mongoose.connect(config.database); // 連線資料庫
app.set('superSecret', config.secret); // 設定app 的超級密碼--用來生成摘要的密碼
//用body parser 來解析post和url資訊中的引數
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
// 使用 morgan 將請求日誌列印到控制檯
app.use(morgan('dev'));
// =======================
// 路由 ================
// =======================
// 基礎路由
app.get('/', function(req, res) {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
// API 路由 -------------------
// 待會兒再新增
// =======================
// 啟動服務 ======
// =======================
app.listen(port);
console.log('Magic happens at http://localhost:' + port);
在火狐上測試
建立一個測試使用者api
app.get('/setup', function(req, res) {
// 建立一個測試使用者
var nick = new User({
name: 'waitifsh',
password: 'test',
admin: true
});
// 將測試使用者儲存到資料庫
nick.save(function(err) {
if (err) throw err;
console.log('User saved successfully');
res.json({ success: true });
});
});
顯示所有使用者api
// API 路由 -------------------
// 獲取一個 express 的路由例項
var apiRoutes = express.Router();
apiRoutes.get('/', function(req, res) {
res.json({ message: 'Welcome to the coolest API on earth!' });
});
// 返回所有使用者資訊
apiRoutes.get('/users', function(req, res) {
User.find({}, function(err, users) {
res.json(users);
});
});
// 應用apiRoutes,並在前面加字首 /api
app.use('/api', apiRoutes);
訪問加了字尾的api介面
返回所有使用者資訊
認證介面
apiRoutes.post('/auth', function(req, res) {
// find the user
User.findOne({
name: req.body.name
}, function(err, user) {
if (err) throw err;
if (!user) {
res.json({ success: false, message: '認證失敗,使用者名稱找不到' });
} else if (user) {
// 檢查密碼
if (user.password != req.body.password) {
res.json({ success: false, message: '認證失敗,密碼錯誤' });
} else {
// 建立token
var token = jwt.sign(user, app.get('superSecret'), {
expiresInMinutes: 1440 // 設定過期時間
});
// json格式返回token
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
錯誤的密碼
正確的密碼返回
使用路由中介軟體保護路由
程式碼如下:
apiRoutes.use(function(req, res, next) {
//檢查post的資訊或者url查詢引數或者頭資訊
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// 解析 token
if (token) {
// 確認token
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'token資訊錯誤.' });
} else {
// 如果沒問題就把解碼後的資訊儲存到請求中,供後面的路由使用
req.decoded = decoded;
next();
}
});
} else {
// 如果沒有token,則返回錯誤
return res.status(403).send({
success: false,
message: '沒有提供token!'
});
}
});