博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
koa+mysql+vue+socket.io全栈开发之web api篇
阅读量:7256 次
发布时间:2019-06-29

本文共 6243 字,大约阅读时间需要 20 分钟。

原文地址:

目标是建立一个 web QQ的项目,使用的技术栈如下:

  1. 后端是基于koa2 的 web api 服务层,提供curd操作的http接口,登录验证使用的是 json web token,跨域方案使用的是 cors
  2. 数据库使用的是 mysql
  3. 为了实时通信,使用的是基于websocket协议的 socket.io 框架;
  4. 前端则使用的是 vue + vuex

本篇则讲叙服务端的搭建,之所以使用 koa,而不使用其他封装过的框架,比如 Egg.jsThinkjs。因为在我看来,koa2 已经够方便,插件也足够多,完全可以根据自己的需求,像搭积木一样构建出最适合业务需求的框架。这样不但摒弃了很多用不到的插件,使整个框架更加精简,也能对整个框架知根知底,减少了很多不可预知因素的影响。

当然我觉得最主要的是我比较懒?,不想再去学其他框架特有的api,特有的配置。因为前端有太多框架太多api需要掌握了,对于非互联网公认的技术标准,我觉得学习的优先级还是要靠后一点的。因为这些个框架,三天两头就冒出个热门的,简直多不胜数,学不过来啊,而koa基本都是这些框架的底层,明显靠谱多了。

基本框架搭建

这几个koa插件大部分项目八九不离十要用到:

  • koa-body 解析http数据
  • koa-compress gzip压缩
  • koa-router 路由
  • koa-static 设置静态目录
  • koa2-cors 跨域cors
  • log4js 老牌的日志组件
  • jsonwebtoken jwt 组件

基本的目录结构

public #公共目录src    #前端目录server #后端目录├── common #工具├── config #配置文件├── controller #控制器├── daos   #数据库访问层├── logs   #日志目录├── middleware  #中间件目录├── socket #socketio目录├── app.js #入口文件└── router.js #路由               复制代码

入口文件app.js

主要就是几个中间件配置需要注意一下,这里同时还加载了 socket.io 服务。socket.io 相关的基本知识点可以看我之前写的文章。

//app.js//...const path = require("path");const baseDir = path.normalize(__dirname + "/..");// gzipapp.use(  compress({    filter: function(content_type) {      return /text|javascript/i.test(content_type);    },    threshold: 2048,    flush: require("zlib").Z_SYNC_FLUSH  }));// 解析请求app.use(  koaBody({    jsonLimit: 1024 * 1024 * 5,    formLimit: 1024 * 1024 * 5,    textLimit: 1024 * 1024 * 5,    multipart: true, // 解析FormData数据    formidable: { uploadDir: path.join(baseDir, "public/upload") }//上传文件目录  }));// 设置静态目录app.use(static(path.join(baseDir, "public"), { index: false }));app.use(favicon(path.join(baseDir, "public/favicon.ico")));//corsapp.use(  cors({    origin: "http://localhost:" + config.clientPort,    credentials: true,    allowMethods: ["GET", "POST", "DELETE"],    exposeHeaders: ["Authorization"],    allowHeaders: ["Content-Type", "Authorization", "Accept"]  }));//json-web-token中间件app.use(  jwt({    secret: config.secret,    exp: config.exp  }));// 登录验证中间件,exclude 表示不验证的页面,include 表示要验证的页面app.use(  verify({    exclude: ["/login", "/register", "/search"]  }));// 错误处理中间件app.use(errorHandler()); // 路由addRouters(router);app.use(router.routes()).use(router.allowedMethods());// 处理404app.use(async (ctx, next) => {  log.error(`404 ${ctx.message} : ${ctx.href}`);  ctx.status = 404;  ctx.body = { code: 404, message: "404! not found !" };});// 处理中间件和系统错误app.on("error", (err, ctx) => {  log.error(err); //log all errors  ctx.status = 500;  ctx.statusText = "Internal Server Error";  if (ctx.app.env === "development") {    //throw the error to frontEnd when in the develop mode    ctx.res.end(err.stack); //finish the response  } else {    ctx.body = { code: -1, message: "Server Error" };  }});if (!module.parent) {  const { port, socketPort } = config;  /**   * koa app   */  app.listen(port);  log.info(`=== app server running on port ${port}===`);  console.log("app server running at: http://localhost:%d", port);  /**   * socket.io   */  addSocket(io);  server.listen(socketPort);}复制代码

跨域cors 和 json web token

这里解释一下 koa-cors 参数的设置,我项目使用的是 json web token,需要把认证字段Authorization添加到header,前端获取该header字段,之后给后台发送http请求的时候,再带上该Authorization。

  • origin:如果要访问header里面的字段或者设置cookie,要写具体的域名地址,用 星号 * 是不行的;
  • credentials:主要是给前端获取cookie;
  • allowMethods:允许访问的方法;
  • exposeHeaders:前端如果要获取该header字段,必须写明(json web token用);
  • allowHeaders:添加到header的字段;

至于 json web token的原理,网上资料齐全,这里不再介绍了。

app.use(  cors({    origin: "http://localhost:" + config.clientPort, // 访问header,要写明具体域名才行    credentials: true, //将凭证暴露出来, 前端才能获取cookie    allowMethods: ["GET", "POST", "DELETE"],    exposeHeaders: ["Authorization"], // 将header字段expose出去    allowHeaders: ["Content-Type", "Authorization", "Accept"] // 允许添加到header的字段  }));复制代码

中间件middleware

koa 的中间件就是 web开发的利器,通过它可以非常方便的实现 强类型语言中的 aop 切面编程,而koa2 中间件 的编写也足够简单 。

项目在以下几个地方都用中间件进行了封装,很多重复的样板代码因此得以简化。

  • json web token(jwt)
  • 登录验证(verify)
  • 错误处理(errorHandler)

就以最简单的错误处理中间件为例子,如果不使用错误处理中间件,我们需要每个控制器方法进行 try{…} catch{…} ,其他中间件编写方式类似,就不再介绍。

/** * error handler 中间件 */module.exports = () => {    return async (ctx, next) => {        try {            await next();//没有错误则进入下一个中间件        } catch (err) {            log.error(err);            let obj = {                code: -1,                message: '服务器错误'            };            if (ctx.app.env === 'development') {                obj.err = err;            }            ctx.body = obj        }    };};// 控制器代码使用error handler中间件后,每个方法都不需要 try catch处理错误,记录错误日志,处理逻辑都集中在中间件里面了。exports.getInfo = async function(ctx) {    // try {
const token = await ctx.verify(); const [users, friends] = await Promise.all([ userDao.getUser({ id: token.uid }), getFriends([token.uid]) ]); const msgs = applys.map(formatTime); ctx.body = { code: 0, message: "好友列表", data: { user: users[0], friends: mergeReads(friends, reads), groups, msgs } }; // } catch (err) {
// log.error(err); // let obj = {
// code: -1, // message: "服务器错误" // }; // if (ctx.app.env === "development") {
// obj.err = err; // } // ctx.body = obj; // }};复制代码

路由配置

路由配置只使用了get,post 方法,当然要使用 put,delete也只是改一下名字就行。

// router.jsconst { uploadFile } = require('./controller/file')const { login, register } = require('./controller/sign')const { addGroup, delGroup, updateGroup } = require('./controller/group')//...module.exports = function (router) {    router        .post('/login', login)        .post('/register', register)        .post('/upload', uploadFile)        .post('/addgroup', addGroup)        .post('/delgroup', delGroup)        .post('/updategroup', updateGroup)  			//...};复制代码

控制器

以updateInfo方法为例,koa2 已经全面支持 async await,编写方式和同步代码没多大区别。

exports.updateInfo = async function (ctx) {    const form = ctx.request.body;    const token = await ctx.verify();    const ret = await userDao.update([form, token.uid]);    if (!ret.affectedRows) {        return ctx.body = {            code: 2,            message: '更新失败'        };    }    ctx.body = {        code: 0,        message: '更新成功'    };}复制代码

后续

接着下一编就是基于 mysql 构建 数据库访问层。

转载于:https://juejin.im/post/5caee295e51d456e7c0cdac7

你可能感兴趣的文章
爬取xml数据之R
查看>>
Xdebug及PHPUnit安装Unknown remote channel: pear.symfony.com
查看>>
网络下载文件及存到sd卡--Android学习笔记
查看>>
web制作、开发人员需知的Web缓存知识
查看>>
SQL Server2005创建新数据库时不允许创建新数据库的问题
查看>>
[推荐] - 中文读物
查看>>
五星评分效果 原生js
查看>>
vue-cli 根据不同的环境打包
查看>>
fatal: could not read Username for 'https://github.com': No such file or directo
查看>>
应用崩溃日志解析
查看>>
安装android的IntelHaxm.exe时出错的问题
查看>>
(四)Java 基础语法
查看>>
俯仰角/偏航角的转化
查看>>
javascript原型
查看>>
51nod 1232:完美数
查看>>
高级排序算法之快速排序
查看>>
关于云计算的一些概念理解
查看>>
《转载》如何使用M6117D看门狗定时器复位系统
查看>>
shell脚本中四则运算
查看>>
day13-堡垒机表结构设计
查看>>