文档章节

koa+mysql+vue+socket.io全栈开发之web api篇

o
 osc_gu9d45li
发布于 2019/04/09 11:40
字数 1534
阅读 9
收藏 0

精选30+云产品,助力企业轻松上云!>>>

原文地址:koa+mysql+vue+socket.io全栈开发之web api篇

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

  1. 后端是基于koa2 的 web api 服务层,提供curd操作的http接口,登录验证使用的是 json web token,跨域方案使用的是 cors

  2. 数据库使用的是 mysql

  3. 为了实时通信,使用的是基于websocket协议的 socket.io 框架;

  4. 前端则使用的是 vue + vuex

<!-- more -->

本篇则讲叙服务端的搭建,之所以使用 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 相关的基本知识点可以看我之前写的文章关于socket.io的使用

//app.js
//...
const path = require("path");
const baseDir = path.normalize(__dirname + "/..");

// gzip
app.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")));

//cors
app.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());

// 处理404
app.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 中间件 的编写也足够简单 koajs

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

  • 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.js
const { 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 构建 数据库访问层。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
koa+mysql+vue+socket.io全栈开发之web api篇

目标是建立一个 web QQ的项目,使用的技术栈如下: 后端是基于koa2 的 web api 服务层,提供curd操作的http接口,登录验证使用的是 json web token,跨域方案使用的是 cors; 数据库使用的是...

Jeff.Zhong
2019/04/09
0
0
koa+mysql+vue+socket.io全栈开发之web api篇

目标是建立一个 web QQ的项目,使用的技术栈如下: 后端是基于koa2 的 web api 服务层,提供curd操作的http接口,登录验证使用的是 json web token,跨域方案使用的是 cors; 数据库使用的是...

edwardzhong
2019/04/11
0
0
koa+mysql+vue+socket.io全栈开发之前端篇

原文地址:koa+mysql+vue+socket.io全栈开发之前端篇 React 与 Vue 之间的对比,是前端的一大热门话题。 vue 简易上手的脚手架,以及官方提供必备的基础组件,比如 vuex,vue-router,对新手...

osc_xgk2otgu
04/16
6
0
koa+mysql+vue+socket.io全栈开发之前端篇

React 与 Vue 之间的对比,是前端的一大热门话题。 vue 简易上手的脚手架,以及官方提供必备的基础组件,比如 vuex,vue-router,对新手真的比较友好;react 则把这些都交给社区去做,虽然这...

Jeff.Zhong
2019/04/13
0
0
koa+mysql+vue+socket.io全栈开发之前端篇

React 与 Vue 之间的对比,是前端的一大热门话题。 vue 简易上手的脚手架,以及官方提供必备的基础组件,比如 vuex,vue-router,对新手真的比较友好;react 则把这些都交给社区去做,虽然这...

JeffZhong
2019/04/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

敖丙20 张图揭开内存管理的迷雾

前言 之前有不少读者跟我反馈,能不能写图解操作系统? 既然那么多读者想看,我最近就在疯狂的复习操作系统的知识。 操作系统确实是比较难啃的一门课,至少我认为比计算机网络难太多了,但它...

敖丙
07/02
15
0
拉勾网拉你上勾

预览 需求简介 拉勾网是一个互联网行业的一个招聘网站,上面有许多职位,于是乎,小编想提取指定职位的基本信息(职位名,薪水,工作经验,工作地点,教育背景),然后插入 MongoDB 数据库,...

木下瞳
2019/04/17
20
0
我是一个线程(第一人称)

来源 | 转自 码农翻身 作者 | 刘欣 全文总共 | 4600 字 预计阅读时间 | 12 分钟 第一回 初生牛犊 我是一个线程,我一出生就被编了个号:0x3704,然后被领到一个昏暗的屋子里,在这里我发现了...

geniusian
2019/11/04
18
0
SkyWalking 权限认证

版本:7.0.0 描述 为了数据传输安全,确保网络连接是安全的。采用 Token 认证确保采集的应用数据是被信任的。 当前版本,仅支持简单的字符串 Token 配置 代理端配置文件agent.config设置 # ...

zm123321
今天
17
0
是否允许实体正文进行HTTP DELETE请求? - Is an entity body allowed for an HTTP DELETE request?

问题: When issuing an HTTP DELETE request, the request URI should completely identify the resource to delete. 发出HTTP DELETE请求时,请求URI应该完全标识要删除的资源。 However,......

javail
昨天
27
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部