1. 程式人生 > >用 nodejs express 搭建 restful api

用 nodejs express 搭建 restful api

本文參考了這篇文章, 英文好的同學,直接移步這裡最終程式碼地址

簡介

搭建一個restful風格的api,資料庫使用mongodb,使用 token 來認證客戶端。

基本流程

  1. 建立受保護和不受保護的路由。
  2. 客戶端通過post使用者名稱和密碼進行驗證,服務端返回一個tokenjson字串。
  3. 客戶端將token儲存在本地,並再每次向服務端發出請求的時候帶上這個token資訊。
  4. 服務端驗證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!'
        });

    }
});

這裡寫圖片描述