node.js 接口调用示例

测试用例git地址(node.js部分):https://github.com/wuyongxian20/node-api.git

项目架构如下:

controllers:

  文件夹下为接口文件

logs:

  log4js 日志打印文件

mongodb:

  mongodb数据库配置及帮助类的封装

mysql:

  mysql数据库配置及数据库的封装

utils:

  帮助类

app.js:

  node.js启动文件

controller.js:

  controller接口封装调用

 

相互关系:

>package.json 项目依赖

>mongodb和mysql为基本的数据库配置和帮助类

>controllers文件夹下的接口引用mongodb和mysql操作数据库

>controller.js是对controllers文件夹的引用和设置api路由跳转

>app.js 加载controller.js文件,即加载所有的controllers文件夹下的接口

 

 

VUE+Node.js接口调用步骤

MySql数据库准备

>mysql 添加测试数据库 rehab(数据库名只需要和mysql\config\index.js中配置文件的数据库名对应起来就行)

>添加测试表test{id:int,name:varchar}

Node.js接口部分(示例中不考虑mongodb数据库使用部分)

1、创建node.js项目,向package.json中写入项目需要的依赖文件,依次是

{
  "name": "node-demo",
  "version": "1.0.0",
  "description": "node demo",
  "main": "app.js",
  "scripts": {
    "start": "supervisor app.js"
  },
  "keywords": [
    "koa",
    "async"
  ], 
  "author": "Michael Liao",
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "https://github.com/michaelliao/learn-javascript.git"
  },
  "dependencies": {
    "koa": "^2.8.1",
    "koa-bodyparser": "^4.2.1",
    "koa-router": "^7.4.0",
    "mongodb": "^3.3.2",
    "mysql": "^2.17.1",
    "q": "^1.5.1",
    "log4js": "^5.2.0"
  }
}
package.json

koa:koa框架

koa-bodyparser:解析表单数据,并放入到ctx.request.body

koa-router:路由

mongod:node的mongodb数据库中间件

mysql:node的mysql数据库中间件

q:Promise处理模块

log4js:日志文件

2、controller.js ,设置GET\POST\PUT\DELETE四种接口的路由,并把controllers文件夹下的所有js文件加载进来

const fs = require('fs');

// add url-route in /controllers:

function addMapping(router, mapping) {
    for (var url in mapping) {
        if (url.startsWith('GET ')) {
            var path = url.substring(4);
            router.get(path, mapping[url]);
           // console.log(`register URL mapping: GET ${path}`);
        } else if (url.startsWith('POST ')) {
            var path = url.substring(5);
            router.post(path, mapping[url]);
           // console.log(`register URL mapping: POST ${path}`);
        } else if (url.startsWith('PUT ')) {
            var path = url.substring(4);
            router.put(path, mapping[url]);
            console.log(`register URL mapping: PUT ${path}`);
        } else if (url.startsWith('DELETE ')) {
            var path = url.substring(7);
            router.del(path, mapping[url]);
          //  console.log(`register URL mapping: DELETE ${path}`);
        } else {
            console.log(`invalid URL: ${url}`);
        }
    }
}

function addControllers(router, dirs) {
    for(let i=0;i<dirs.length;i++){
        fs.readdirSync(__dirname + '/' + dirs[i]).filter((f) => {
            return f.endsWith('.js');
        }).forEach((f) => {
          //  console.log(`process controller: ${f}...`);
            let mapping = require(__dirname + '/' + dirs[i] + '/' + f);
            addMapping(router, mapping);
        });
    }
  
}

module.exports = function (dir) {
    let
        controllers_dir = dir || 'controllers',
        router = require('koa-router')();
        debugger
        let controllers=['controllers','controllers/admin']
    addControllers(router, controllers);
   // addControllers(router, 'controllers/admin');
    return router.routes();
};


// function addControllers(router, dir) {
//     fs.readdirSync(__dirname + '/' + dir).filter((f) => {
//         return f.endsWith('.js');
//     }).forEach((f) => {
//         console.log(`process controller: ${f}...`);
//         let mapping = require(__dirname + '/' + dir + '/' + f);
//         addMapping(router, mapping);
//     });
// }

// module.exports = function (dir) {
//     let
//         controllers_dir = dir || 'controllers',
//         router = require('koa-router')();
//         debugger
//     addControllers(router, controllers_dir);
//    // addControllers(router, 'controllers/admin');
//     return router.routes();
// };
controller.js

3、app.js

const Koa = require('koa');

const bodyParser = require('koa-bodyparser');

const controller = require('./controller');

const app = new Koa();

//log4js 日志配置
var log4js = require('log4js');
log4js.configure('./config/log4js.json');

// log request URL:
app.use(async (ctx, next) => {
    //添加允许请求头
    ctx.append('Access-Control-Allow-Origin', '*')
    ctx.append('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild')
    // ctx.append('Content-Type', 'application/json;charset=utf-8')
    ctx.append('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS,PATCH')
    console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
    //http 预请求处理(post/put/delete 请求在正式请求之前会先发送一个OPTIONS的预请求,只需要把这个OPTIONS的预请求正常返回,后续的请求就会正常执行)
    if (ctx.request.method === 'OPTIONS') {
        ctx.body = "OK"
    } else {
        //继续执行api请求
        await next();
    }

});

// parse request body:
app.use(bodyParser());

// add controller:
app.use(controller());

app.listen(3000);
console.log('app started at port 3000...');
app.js

app.js做的事情是

>加载koa框架

>加载form参数解析的中间件koa-bodyparser

>加载log4js日志配置文件

{
    "appenders": {
      "console": {
        "type": "console"
      },
      "trace": {
        "type": "dateFile",
        "filename": "./logs/access-",
        "pattern": ".yyyy-MM-dd.log",
        "alwaysIncludePattern": true,
        "maxLogSize ": 31457280
      },
      "http": {
        "type": "logLevelFilter",
        "appender": "trace",
        "level": "trace",
        "maxLevel": "trace"
      },
      "info": {
        "type": "dateFile",
        "filename": "./logs/info-",
        "encoding": "utf-8",
        "pattern": ".yyyy-MM-dd.log",
        "maxLogSize": 10000000,
        "alwaysIncludePattern": true,
        "layout": {
          "type": "pattern",
          "pattern": "[%d{ISO8601}][%5p  %z  %c] %m"
        },
        "compress": true
      },
      "maxInfo": {
        "type": "logLevelFilter",
        "appender": "info",
        "level": "debug",
        "maxLevel": "error"
      },
      "error": {
        "type": "dateFile",
        "filename": "./logs/error-",
        "pattern": ".yyyy-MM-dd.log",
        "maxLogSize": 10000000,
        "encoding": "utf-8",
        "alwaysIncludePattern": true,
        "layout": {
          "type": "pattern",
          "pattern": "[%d{ISO8601}][%5p  %z  %c] %m"
        },
        "compress": true
      },
      "minError": {
        "type": "logLevelFilter",
        "appender": "error",
        "level": "error"
      }
    },
    "categories": {
      "default": {
        "appenders": [
          "console",
          "http",
          "maxInfo",
          "minError"
        ],
        "level": "all"
      }
    }
  }
log4js.json

>加载api路由 controller.js

>请求url处理

app.use(async (ctx, next) => {
    //添加允许请求头
    ctx.append('Access-Control-Allow-Origin', '*')
    ctx.append('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild')
    // ctx.append('Content-Type', 'application/json;charset=utf-8')
    ctx.append('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS,PATCH')
    console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
    //http 预请求处理(post/put/delete 请求在正式请求之前会先发送一个OPTIONS的预请求,只需要把这个OPTIONS的预请求正常返回,后续的请求就会正常执行)
    if (ctx.request.method === 'OPTIONS') {
        ctx.body = "OK"
    } else {
        //继续执行api请求
        await next();
    }
});

  >>ctx.append()

    添加请求头,目的在服务器端解决跨域问题

  >> ctx.request.method === 'OPTIONS'处理

    请求在正式请求之前会先发送一个OPTIONS的预请求,只需要把这个OPTIONS的预请求正常返回,后续的请求就会正常执行

  >>await next()

    当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并    且每个中间件恢复执行其上游行为。

>启动端口监听,启动项目

 

4、api接口(以处理mysql数据的接口为例)

controllers文件夹下创建mysqlapi.js文件

let util = require('../utils/util')
const db = require('../mysql/mysql.js')
var logger = require('log4js').getLogger("index");
let util_http = require('../utils/util_http')


module.exports = {

    /**
     * 根据数据表名查询全部
     */
    'GET /mysql/findAll': async (ctx, next) => {
        ctx.response.type = 'application/json';

        let table = ctx.request.query.table
        let sql = `select * from ${table}`
        await db.selectAll(sql).then(res => {
            ctx.body = util.res(res)
        }).catch(err => {
            ctx.body = util.err(err)
        })
    },
    /**
     * 根据数据表名和指定查询条件查询
     */
    'GET /mysql/findBy': async (ctx, next) => {
        ctx.response.type = 'application/json';
        ctx.append('Access-Control-Allow-Origin', '*')
        let table = ctx.request.body.table
        let where = ctx.request.body.where
        await db.selectBy(table, where).then(res => {
            ctx.body = util.res(res)

        }).catch(err => {
            ctx.body = util.err(err)
        })
    },
    /**
     * 根据数据表名和id查询
     */
    'GET /mysql/findById': async (ctx, next) => {
        ctx.response.type = 'application/json';
        ctx.append('Access-Control-Allow-Origin', '*')
        let table = ctx.request.query.table
        let id = ctx.request.query.id
        let sql = `select * from ${table} where id='${id}'`
        await db.selectAll(sql).then(res => {
            ctx.body = util.res(res)

        }).catch(err => {
            ctx.body = util.err(err)
        })
    },

    /**
     * 添加数据
     */
    'POST /mysql/add': async (ctx, next) => {
        // ctx.response.type = 'application/json'; 
        // ctx.res.header('Access-Control-Allow-Origin', '*');

        if (ctx.req.method == 'POST') {
            let data = await util_http.getPOSTRes(ctx.req)
            data = JSON.parse(data)
            let table = data.table
            let params = data.params
            await db.insertData(table, params).then(res => {
                ctx.body = util.res(res)
            }).catch(err => {
                ctx.body = util.err(err)
            })
        } else {
            ctx.body = util.err('请求错误')
        }


    },
    /**
     * 更新数据
     */
    'PUT /mysql/update': async (ctx, next) => {
        if (ctx.req.method == 'PUT') {
            let data = await util_http.getPOSTRes(ctx.req)
            data = JSON.parse(data)
            let table = data.table
            let sets = data.sets
            let where = data.where
           // console.log('sql', table, sets, where)
            await db.updateData(table, sets, where).then(res => {
                ctx.body = util.res(res)
            }).catch(err => {
                ctx.body = util.err(err)
            })
        } else {
            ctx.body = util.err('请求错误')
        }
    },
    // /**
    //  * 更新数据
    //  */
    // 'PATCH /mysql/patch': async (ctx, next) => {
    //     // ctx.response.type = 'application/json';
    //     console.log('patch init')
    //     ctx.body = '2222'
    //     //ctx.body=util.res('123')
    //     // console.log('request',ctx.request)
    //     // let table = ctx.request.body.table
    //     // console.log('table',table)
    //     // let sets = ctx.request.body.sets
    //     // let where = ctx.request.body.where
    //     // await db.updateData(table, sets, where).then(res => {
    //     //     ctx.body = util.res(res)
    //     // }).catch(err => {
    //     //     ctx.body = util.err(err)
    //     // })
    // },
    /**
     * 删除数据
     */
    'DELETE /mysql/delete': async (ctx, next) => {  
        let table = ctx.request.body.table
        let where = ctx.request.body.where
        await db.deleteData(table, where).then(res => {
            ctx.body = util.res(res)
        }).catch(err => {
            ctx.body = util.err(err)
        })
    },
    /**
     * 根据数据表名和id删除数据
     */
    'DELETE /mysql/deleteById': async (ctx, next) => {
        ctx.response.type = 'application/json';
        ctx.append('Access-Control-Allow-Origin', '*')
        let table = ctx.request.query.table
        let id = ctx.request.query.id
        let where = {
            id: id
        }
        await db.deleteData(table, where).then(res => {
            ctx.body = util.res(res)
        }).catch(err => {
            ctx.body = util.err(err)
        })
    }
};
node.js api接口示例

>get 接口中使用ctx.request.query接收Params方式传递的表单参数

>post接口中使用ctx.request.body接收body方式传递的表单参数

  >>post接口中,需要使用监听方式接收表单数据(req.on('data',(chunk)=>{}))+req.on('end',()=>{}))

let util_http={
    /**
     * 接口执行成功统一回复格式
     * @param {*} result 返回结果 
     * @param {*} code 返回代码
     * @param {*} msg 返回消息
     */
    async getPOSTRes(req){
       return new Promise((resolve,reject)=>{
        let data = '';
        //2.注册data事件接收数据(每当收到一段表单提交的数据,该方法会执行一次)
        req.on('data', function (chunk) {
            // chunk 默认是一个二进制数据,和 data 拼接会自动 toString
            data += chunk;
        });

        // 3.当接收表单提交的数据完毕之后,就可以进一步处理了
        //注册end事件,所有数据接收完成会执行一次该方法
        req.on('end', function () {
            //(1).对url进行解码(url会对中文进行编码)
            data = decodeURI(data);
            resolve(data)
        });
       })
    }
   
}

module.exports=util_http
body表单数据接收

  接收参数时(包括接口中调用mysql接口时),均需要借助async,await关键字,将代码执行的控制权交给下一级中间件,待下一级中间件执行完成后,继续后续代码操作

另附mysql文件夹下的mysql配置文件和mysql操作文件

const mysql = require('mysql')

const connectdb=()=>{
  let connection = mysql.createConnection({
    host     : 'localhost',
    port     : '3306',
    user     : 'root',
    password : '',
    database : 'rehab'
  }) 
  return connection;
}

module.exports=connectdb;
mysql配置文件
const conn = require('./config/index');
const connection = conn();

// 查询所有数据
let selectAll = async(sql,callback)=>{
  return sqlQuery(sql)
}
let selectBy = async(table,where,callback)=>{
    var _WHERE='';
    // var keys='';
    // var values='';
    for(var k2 in where){
        _WHERE+=k2+"='"+where[k2]+"' AND ";
      //_WHERE+= k2+"='"+where[k2]+"'";
    }
    _WHERE=_WHERE.slice(0,-5)
    // UPDATE user SET Password='321' WHERE UserId=12
    //update table set username='admin2',age='55'   where id="5";
    var sql="SELECT * FROM "+table+' WHERE '+_WHERE;
   // console.log(sql);
    return sqlQuery(sql)
}
// 插入一条数据
let insertData =async (table,datas,callback)=>{
  var fields='';
  var values='';
  for( var k in datas){
      fields+=k+',';
      values=values+"'"+datas[k]+"',"
  }
  fields=fields.slice(0,-1);
  values=values.slice(0,-1);
 // console.log(fields,values);
  var sql="INSERT INTO "+table+'('+fields+') VALUES('+values+')';
  return sqlQuery(sql)
}

/**
 * 更新一条数据
 * @param {*} table 数据表名
 * @param {*} sets 更新字段
 * @param {*} where 限制条件
 */
let updateData=async function(table,sets,where){
    var _SETS='';
    var _WHERE='';
    var keys='';
    var values='';
    for(var k in sets){
        _SETS+=k+"='"+sets[k]+"',";
    }
    _SETS=_SETS.slice(0,-1);
    for(var k2 in where){
        _WHERE+=k2+"='"+where[k2]+"' AND ";
      //_WHERE+= k2+"='"+where[k2]+"'";
    }
    _WHERE=_WHERE.slice(0,-5)
    // UPDATE user SET Password='321' WHERE UserId=12
    //update table set username='admin2',age='55'   where id="5";
    var sql="UPDATE "+table+' SET '+_SETS+' WHERE '+_WHERE;
   // console.log(sql);
    return sqlQuery(sql)
}

// 删除一条数据
let deleteData=function(table,where,callback){
    var _WHERE='';
    for(var k2 in where){
       _WHERE+=k2+"='"+where[k2]+"' AND ";
      //_WHERE+= k2+"="+where[k2];
    }
    _WHERE=_WHERE.slice(0,-5)
    // DELETE  FROM user WHERE UserId=12  注意UserId的数据类型要和数据库一致
    var sql="DELETE  FROM "+table+' WHERE '+_WHERE;
   // connection.query(sql,callback);
    return sqlQuery(sql)
}

let sqlQuery=function(sql){
  return new Promise((resolve,reject)=>{
    connection.query(sql,(err,result)=>{
      if(err){
          console.log('错误信息-',err.sqlMessage);
          let errNews = err.sqlMessage;
          reject(errNews)
      } else{
        resolve(result)
      }
    })
  })
}
module.exports = {
  selectAll,
  selectBy,
  insertData,
  deleteData,
  updateData,
}
mysql操作文件

 

VUE操作(接口调用操作)

1、Vue-cli 3.0搭建项目,配置package.json项目依赖,添加vue.js文件,配置vue文件路由,main.js的组件引用操作省略

2、测试文件

<template>
<div class="api">
    <div class="api-item">
        <van-button type="default" @click="getTest">get test</van-button>
    </div>
    <div class="api-item">
        <van-field v-model="name.add" placeholder="请输入name" />
        <van-button type="default" @click="addTest">add test</van-button>
    </div>
    <div class="api-item">
        <van-field v-model="name.update_set" placeholder="请输入更改值" />
        <van-field v-model="name.update_where" placeholder="请输入初始值" />
        <van-button type="default" @click="updateTest">update test</van-button>
    </div>
    <div class="api-item">
        <van-field v-model="name.delete" placeholder="请输入删除值" />
        <van-button type="default" @click="deleteTest">delete test</van-button>
    </div>
    <div class="api-item api-result">
        <p>result:</p>
        <p>code:{{result.code}}</p>
        <p>msg:{{result.msg}}</p>
        <p>result:{{result.result}}</p></div>
</div>
</template>

<script>
    import {api} from "../../api/server";

    export default {
        name: "apitest",
        data(){
            return{
                openid:'28d91cb4-28a6-4110-b401-a6ca03cddf27',
                result:'',
                name:{
                    add:'22',
                    update_set:'44',
                    update_where:'33',
                    delete:'2233'
                },
                msg:''
            }
        },
        methods:{
            getTest(){
                let params={
                    table:'test'
                }
                let that=this;
                api.get(params).then(res=>{
                    console.log('res',res)
                    that.result=res
                }).catch(err=>{
                    console.log('err',err)
                    that.result=err
                })
            },
            addTest(){
                if(this.name.add==''){
                    this.Toast('请输入name');
                    return false
                }
                let params= {
                    table: 'test',
                    params: {
                        id: this.util.randomNum(),
                        name: this.name.add
                    }
                }
                let that=this;
                api.add(params).then(res=>{
                    console.log('res',res)
                    that.result=res
                }).catch(err=>{
                    console.log('err',err)
                    that.result=err
                })
            },
            updateTest(){
                if(this.name.update_where==''||this.name.update_set==''){
                    this.Toast('请输入name');
                    return false
                }
                let params= {
                    table: 'test',
                    sets: {
                        name:this.name.update_set
                    },
                    where: {
                        name:this.name.update_where
                    }
                }
                // let params={
                //     id:'11',
                //     name:'22'
                // }
                let that=this;
                api.update(params).then(res=>{
                    console.log('res',res)
                    that.result=res
                }).catch(err=>{
                    console.log('err',err)
                    that.result=err
                })
            },
            deleteTest(){
                if(this.name.update_where==''||this.name.update_set==''){
                    this.Toast('请输入name');
                    return false
                }
                let params= {
                    table: 'test',
                    where: {
                        name:this.name.delete
                    }
                }
                // let params={
                //     id:'11',
                //     name:'22'
                // }
                let that=this;
                api.delete(params).then(res=>{
                    console.log('res',res)
                    that.result=res
                }).catch(err=>{
                    console.log('err',err)
                    that.result=err
                })
            },
        }
    }
</script>

<style lang="less" scoped>
.api{
    text-align: left;
    background-color: #ffffff;
    .api-item{
        margin: 8px;
    }
}
</style>
vue测试页

 3、api接口

import axios from 'axios';
 const server = 'http://localhost:3000';

export  const api={
    get(params){
        return axios.get(server + '/mysql/findAll', {params});
    },
    add(params){
      let headers = {'Content-Type': 'multipart/form-data'}
       return axios.post(server + '/mysql/add', params, {headers});
    },
    update(params){
         let headers = {'Content-Type': 'multipart/form-data'}
       return axios.put(server + '/mysql/update', params,{headers});
    },
    delete(params){
        let headers = {'Content-Type': 'multipart/form-data'}
        return axios.delete(server + '/mysql/delete', {data:params},{headers});
    },
}
vue api接口

> 示例中使用的是axios组件调用的api接口

> params接口参数形式说明

  >> get接口参数需要使用{}包裹,如{params}

  >> post\put接口直接添加params参数

  >> delete接口需加上'data'说明,如{data:params}

>headers

  >> post\put\delete三种方式需要添加请求头header设置 headers = {'Content-Type': 'multipart/form-data'}

  在node.js中接收方式为ctx.request.body

  >> get方式请求不需要加请求头,在node.js中接收方式为ctx.request.query

  >> put\delete 请求方式在发送请求前会先发送预请求命令,请求方式为OPTIONS,这时只需要在node.js中正常返回,不需要做任何处理

 

最后,展示几种接口在postman中的调用方式

 

posted on 2019-10-26 16:50  eye_like  阅读(5800)  评论(0编辑  收藏  举报