nodejs开发服务端

161 阅读6分钟

nodejs开发服务端

mongodb

全局安装express-generator

npm i express-generator -g

搭建express后端项目

express express_project

项目结构

  1. app.js——项目入口(主要配置接口的一级路径和引入表现层)
  2. routes——表现层(将服务层返回的处理结果响应给前端)
  3. service——服务层(对持久层返回的数据操作结果进行逻辑处理)
  4. dao——持久层
    1. models——存放mongoose构建的数据模型
    2. database.js——连接数据库
    3. studentDao.js——数据库操作代码(增删改查)

安装nodemon插件

npm i nodemon -g

更改app.js文件项目启动方式

// module.exports = app;

// 更改启动命令,全局安装nodemon,服务器代码发生更改自动重启项目
app.listen(3000, () => {
  console.log('3000端口启动成功');
});

dao/database.js连接mongodb

/* 连接数据库代码 */

// 引入mongoose
const mongoose = require('mongoose');
// 定义数据库地址
const dbURL = 'mongodb://127.0.0.1:27017/users';
// 开始连接数据库
mongoose.set('strictQuery', false);
mongoose.connect(dbURL);
mongoose.connection.on('connected', () => {
  console.log(dbURL, '数据库连接成功');
});

数据模型构建示例

// 数据集合配置
const { model, Schema } = require('mongoose');

// 定义集合结构,数据类型,Schema是构造函数 需要new
const studentSchema = new Schema(
  {
    // 定义集合中数据类型
    username: String,
    password: String,
    // 需要定义id类型时,Schema.Types.ObjectId
  },
  { versionKey: false }
);

// 用定义好的集合结构来构造数据模型 参数(模型名字,模型结构,集合名字)
const studentModel = model('studentModel', studentSchema, 'students');

module.exports.studentModel = studentModel;

持久层示例

const { teacherModel } = require('./model/teacherModel');

// 查询所有教师
module.exports.getTeachers = async () => {
  return await teacherModel.find();
};

// 添加
module.exports.addTeacher = async data => {
  return await teacherModel.create(data);
};

// 删除
module.exports.delTeacher = async id => {
  // 删除满足条件的一条数据 deleteOne
  return await teacherModel.deleteOne(id);
};

服务层示例

const { getTeachers, addTeacher, delTeacher } = require('../dao/teacherDao');

// 获取
module.exports.getTeachers = async () => {
  try {
    const list = await getTeachers();
    return {
      msg: 'success',
      status: 1,
      list,
    };
  } catch (error) {
    console.log('error--->', error);
    return {
      msg: 'error',
      status: 0,
    };
  }
};

表现层示例

var express = require('express');
var router = express.Router();
// 服务层方法
const { getTeachers, addTeacher,delTeacher } = require('../service/teacherService');

// 获取教师列表
router.get('/getTeachers', async function (req, res, next) {
  const res1 = await getTeachers();
  res.send(res1);
});
// 添加
router.post('/addTeacher', async function (req, res, next) {
  const form=req.body
  const res1 = await addTeacher(form);
  res.send(res1);
});
// 删除
router.post('/delTeacher', async function (req, res, next) {
  const id=req.body
  const res1 = await delTeacher(id);
  res.send(res1);
});

module.exports = router;

一些API(ps:这些方法都是异步的)

1.添加数据 teacherModel.create(object)
2.删除数据 teacherModel.deleteOone(object) 
3.修改数据 teacherModel.updateOne(object) 
4.查询数据 teacherModel.find(object) 没有参数全部返回
  4.1 多表联查 teacherModel.find().populate('studentId') 教师联查学生表
  4.2 多表联查 teacherModel.find().populate('studentId').populate('staffId') 教师联查学生,教师联查员工
  4.3 多表联查 teacherModel.find().populate({
    path:'studentId',
    populate:{
      path:'staffId'
    }
  }) 教师联查学生,学生联查员工
  4.4 限制请求条数 teacherModel.find(object).limit(number)  
  4.4 跳过请求条数 teacherModel.find(object).skip(number)
  4.5 统计数据条数 teacherModel.countDocuments()

密码加密方式

  1. md5

  2. bcrypt

    1. npm i bcrypt
      
    2. const newPwd = bcrypt.hashSync(pwd) 参数传入用户输入的密码
      
    3. 登录时,将用户输入的密码,与根据用户名在数据库查找出来的账户密码进行对比,返回布尔值true或false,判断用户是否输入正确

      const isLogin = bcrypt.compareSync(password, res[0].password); 
      

身份认证token

安装json web token插件

npm i jsonwebtoken
jwt用法
const jwt = require('jsonwebtoken')
// 生成token的参数:存储的用户信息,密钥字符串(随便写),过期时间
const token = jwt.sign({ username }, 'isSign', { expiresIn: 60 });

安装express-jwt插件(用于验证token)

npm i express-jwt
暴露jwt验证
// 后端开始验证 utils/jwt.js 如果方法报错,自行去npm官网检查语法是否有更新
const { expressjwt: jwt } = require('express-jwt');

const jwtAuth = jwt({
  secret: 'isSign', // 验证的密钥字符串
  algorithms: ['HS256'], // 设置jwt的算法为HS256 新版插件配置参数
  credentialRequired: false, // 不带token的请求头是否验证 false——不需验证,直接报错即可
}).unless({
  path: ['/users/login', '/users/isAccess', '/users/register'], // 设置不需要携带token的路径
});

module.exports = jwtAuth;
在app.js文件,配置一级路径前去验证token
const jwtAuth = require('./utils/jwt.js')

app.use(jwtAuth)

jwt解码token,获取用户信息

  • 因为生成token的时候,存放了用户的部分信息,所以通过对token解码,可以获取到这部分内容
  • 生成token时也可以放入用户ID,解码时获取ID,通过ID获取到用户在数据库中的信息
// 解码,认证身份
router.get('/isLogin', async function (req, res, next) {
  let authStr = req.get('Authorization');
  authStr = authStr.split(' ')[1];
  const { username } = jwt.verify(authStr, 'isSign');
  res.send({
    msg: 'success',
    status: 1,
    username,
  });
});

RESTful接口规范

  • 这是一种对于后端的接口规范,主要体现在接口路径以及请求类型上

    1.接口统一使用单一的一级路径,例如 '/user'
    2.请求类型
    	get			查询,获取
    	post		提交
    	put			修改
    	delete	删除
    3.如果接口需要传id,统一在接口路径拼接
    	前端发送		'/user' + id
    	后端接收		'/user:id'  回调参数中使用	req.query接收
    	最好不要混淆规范方式,这种id接收方式不会辨别还有没有二级路由
    

跨域处理

jsonp

  • axios不适用
  • 只能解决get请求
$.ajax({
    url: "http://10.128.119.119/api/get/username",
    type: "GET",
    dataType: "jsonp",       
});

CORS

// app.js var app = express(); 的下面位置添加代码
var app = express();

var allowCrossDomain = function (req, res, next) {
  // 设置允许跨域访问的请求源(* 表示接受任意域名的请求)
	res.header("Access-Control-Allow-Origin","*");
  // 设置允许跨域访问的请求头,如果请求包含token,还要加上Authorization
  res.header("Access-Control-Allow-Headers","X-Requested-With,Origin,Content-Type,Accept,Authorization");
  // 设置允许跨域访问的请求类型
  res.header("Access-Control-Allow-Methods","PUT,POST,DELETE,GET,OPTIONS,PATCH");
  // 同意cookie 发送到服务器(如果要发送cookie,Access-Control-Allow-Origin 不能设置为*)
  res.header("Access-Control-Allow-Credentials","true");
  next();
}

app.use(allowCrossDomain)

代理服务器中间层nodejs

  • 传统的开发中存在着前后端之前还有一层nodejs中间层交给前端处理请求响应逻辑

  • 在这个中间层可以做一些数据的额外处理

  • 步骤

    • 创建一个中间层nodejs项目

    • 在中间层项目中安装http-proxy-middleware

      npm i http-proxy-middleware
      
    • app.js文件,一级路径配置之前配置代理

      const { createProxyMiddelware } = require('http-proxy-middleware')
      
      const options = {
      	target: 'http://localhost:3000', // 目标服务器的host
      	changeOrigin: true // 是否需要改变原始主机头为目标
      	pathRewrite:{ // 重写请求
      		'^/api': '/', // 所有以'/api'开头的请求,'/api'都会重写为 '/'
      	}
      }
      
      // 写在 var app = express(); 之后
      app.use('/api', createProxyMiddleware(options)); // proxy(options)即创建代理
      
    • 大部分情况下可以通过上述方式代理转发,但是登录注册这类请求,需要现在中间层作额外加密处理,再进行转发,这个时候http-proxy-middleware中间件就不可用了

    • 需要用到另外的模块request-promise

      npm i request request-promise
      
    • 这些数据处理需要数据进到路由开始处理

    • 在中间层进行数据处理后,利用request-promise发给后端

      const rp = require('request-promise')
      
      router.get('/isLogin', async function (req, res, next) {
        const data=rp({
          method: 'post',
          url: 'http://localhost:3001/user/login', // 后端服务器请求路径
          body: {
            username,
            password,
          },
          json:true // 需要后端返回json格式
        });
        // 数据返回给前端
        res.send(data)
      });