IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]用 nodejs express 搭建 restful api

    qcpm1983发表于 2015-05-11 15:41:45
    love 0

    本文参考了这篇文章, 英文好的同学,直接移步这里。最终代码地址

    简介

    搭建一个restful风格的api,数据库使用mongodb,使用 token 来认证客户端。

    基本流程

    1. 创建受保护和不受保护的路由。
    2. 客户端通过post用户名和密码进行验证,服务端返回一个token的json字符串。
    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!'
            });
    
        }
    });
    

    这里写图片描述



沪ICP备19023445号-2号
友情链接