magic 发布的文章

Serverless实战驾校小程序【数据库设计】一

从今天开始,我会文字直播开发这个驾校小程序整个流程。
image.png

1. 项目要求

  1. 小程序端
  2. WEB管理后台
  3. 时间在最短的时间内上线

2. 项目功能

参考驾考宝典、主栏目分为科目一、科目四、满分学习、注销恢复、资格证,包含小车、客车、摩托车等,功能包含视频讲解、章节练习、模拟考试、错题、收藏等等。 支持支付、分享、提成、提现等

3. 项目选型

由于要求最快时间内上线,我们小程序选择 Serverless架构。 这里使用以下技术产品

小程序端:

  1. Bmob后端云+iview
  2. VUE + Bmob后端云

Bmob后端云,自带了支付,生成二维码等接口,这里集成可以快速上线。VUE 有丰富的后台模板,可以更快的做出管理后台。

第一步:清晰了解需求

因为已经很清楚自己要做的是驾校答题小程序,这里就不做多余的介绍了。 设计部分,由于这个项目比较小,没有专门的设计师。 尽量参考行业老大:驾校一点通与驾考宝典。

第二步:数据库设计

数据库参考其他驾考类小程序,优先把核心字段建立出来,尽量考虑周全, 不够后面再补。 这里注意的是,Serverless架构,主要适合做一些中小型应用,如果应用数据量很大, 尽量提前考虑分表。

1. 数据表

目前第一阶段暂时考虑一下表

  1. 题目表
  2. 题目类别表(题形)
  3. 错题表
  4. 收藏表
  5. 成绩表
  6. 用户表

用户表,由于Bmob系统自带了,我就不建立了。

2. 数据库文档

由于使用Bmob后端云数据库,默认每条记录都带id、创建时间与更新时间,此数据表说明不带这2个字段。

题目表(question)

名称类型描述
titlestring题目名称
choseListArray选择列表 [{"item":"选选一"},{"item":"选选二","isChose":true}]
typeint类型 1.单选 2.多选 3.判断
picstring图片地址
videostring视频地址
helpstring帮助描述
bSubjectsint所属科目 1.科目一 2.科目四
bModelsint所属车型 1.小车 2.货车 3.客车 4.摩托车
bTypestring所属类别 关联类别表

题目类别表(questionType)

名称类型描述
bSubjectsstring所属科目 1.科目一 2.科目四
titlesting类别名称

错题表

名称类型描述
idstring题目id
uidstring用户id

收藏表

名称类型描述
idstring题目id
uidstring用户id

成绩表

名称类型描述
timestring用时
scoreint成绩

设计好数据表之后,做准备工作

  1. 拿到小程序的 AppID填写到Bmob控制台,应用设置-》应用配置
  2. 把上面所有想好建立好的数据表添加到数据库
  3. 小程序开发工具新建一个空白项目,复制BmobSDK,到utils目录
  4. 引入SDK,初始化。

引入SDK,初始化。文档在这里

https://bmob.github.io/hydrogen-js-sdk/#/?id=%E5%88%9D%E5%A7%8B%E5%8C%96

看最终效果如下。

效果一:所写代码➕预览
WX20180927-143917@2x.png

效果二:数据表变化
image.png

这样我们就实现了,整个小程序开发的第一步,自动注册登陆,获取openid。 第一节就到这里,下一步就是操作业务表。

什么是微信开发第一步?

微信公众平台开发第一步详解

如果有人问你,微信体系下,开放平台、公众号、小程序开发第一步是做什么?

我的回答是获取微信access_token。access\_token是公众号的全局唯一接口调用凭据, 没有凭据后面的其他接口,都没法调用。

公众号调用各接口时都需使用access\_token。开发者需要进行妥善保存。access\_token的存储至少要保留512个字符空间。access\_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access\_token失效。

官方文档地址:
[https://mp.weixin.qq.com/wiki?t\=resource/res\_main\&id\=mp1421140183](https://mp.weixin.qq.com/wiki?t\=resource/res\_main\&id\=mp1421140183)

接口地址

https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数说明

参数是否必须说明grant\_type是获取access\_token填写client\_credentialappid是第三方用户唯一凭证secret是第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

调试工具
微信官方为了大家开发公众号时,提供大家的开发效率,特地给开发者上线了一套调试工具

[https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t\=index\&type\=](https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t\=index\&type\=)基础支持\&form\=获取access\_token接口%20/token

功能实现
这个功能,只需要调用这个接口,然后返回access\_token,我们就不搭建Liunx,PHP,node等环境,直接用当今流行的Serverless 相关平台的Faas(云函数)功能。 这里使用的是Bmob后端云,当然你用阿里、腾讯、华为等等厂商支持Faas(云函数) 功能的都可以,只是语法稍微有点不同,这些开发小程序、公众号都可以。 比自己搭建服务器要快很多。

前期准备
第一步:准备配置信息
登陆微信平台

[https://mp.weixin.qq.com/](https://mp.weixin.qq.com/)

进入开发-》基本配置

image.png

拿到

开发者ID(AppID)与开发者密码(AppSecret),开发请求时需要用到。

第二步:编写云函数
首先你有个Bmob后端应用,点击进入云函数。选择模板创建,当然你也可以自己变。

云函数

自己编写代码,我们有一点javascript基础,或者java基础都可以。这里介绍下Nodejs

文档地址:[http://doc.bmob.cn/cloud\_function/web/develop\_doc/http\_1](http://doc.bmob.cn/cloud\_function/web/develop\_doc/http\_1)

HTTP请求对象
oHttp对象可以模拟实现get、post、put、delete等各种HTTP请求信息,让你在云端实现诸如数据采集、OAuth授权登录等功能。Bmob的HTTP请求模块采用Nodejs提供的request模块,这里提供简单的Get和Post的操作实例。更多的功能详细参考:https://npmjs.org/package/request/**
*发起Get请求
*///获取Http模块var http = modules.oHttp;//发起Get请求http('https://www.bmob.cn', function (error, res, body) {
    response.send(body);
});

-
/**
*发起Post请求
*///获取Http模块var http = modules.oHttp;
var options = {
  "url": 'https://api.bmob.cn/1/classes/GameScore',
  "headers": {
    'X-Bmob-Application-Id': 'Your Application ID',
    'X-Bmob-REST-API-Key': 'Your REST API Key',
    'Content-Type': 'application/json'  },
  "body":JSON.stringify({"score":1337,"playerName":"Sean Plott"})
};
http.post(options, function(error, res, body) {
    response.send(body);
});

微信access\_token,这里只需要发起一个get请求,地址是这样。

[https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t\=index\&type\=](https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t\=index\&type\=)基础支持\&form\=获取access\_token接口%20/token

/**
*发起Get请求
*///获取Http模块var http = modules.oHttp;
var url ="https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=基础支持&form=获取access_token接口%20/token";//发起Get请求http(url, function (error, res, body) {
    response.send(body);
});

不到10行代码,我们就可以拿到微信开发必备的access\_tokenaccess\_token微信是有次数限制的,当然不能这么每次获取使用, 这样只要请求次数多,每月必定超出微信给的次数。 微信官方说:access\_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access\_token失效, 那我们就给这个函数的结果保存到数据库,做个定时任务2小时执行一次。然后需要时读取数据库,这样就不会担心超了。

第三步:access\_token保存数据库
我们在控制台建一个WeiXin\_access\_token表,增加access\_token字段,里面随便增加一条记录,拿到id,用来更新这条记录。当然你也可以把每次获取的access\_token插入到这个表,需要的时候获取到最新的一条。

云函数数据表操作文档:[http://doc.bmob.cn/cloud\_function/web/develop\_doc/\_9](http://doc.bmob.cn/cloud\_function/web/develop\_doc/\_9)

function onRequest (request, response, modules) {

  //获取数据库对象  var db = modules.oData;
  //这里放到表里的ID  var objectId = 'NJEi333B';

  //http请求方式: GET  var appid = 'wxd1b8c236059cd569';
  var secret = 'c18a43c67c81400980624c03c5f11a34';
  var url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + appid + '&secret=' + secret;
  //获取Http模块  var http = modules.oHttp;
  //发起Get请求  http(url, function (error, res, body) {
    if (!error && res.statusCode == 200) {
      //写入数据库      var resultObject = JSON.parse(body);
      //如果返回错误则打印      if (resultObject.errcode) {
        response.send(resultObject);
      }
        
    //更新到数据表      db.update({
        "table": "WeiXin_access_token",
        "objectId": objectId,
        "data": { "access_token": resultObject.access_token }
      }, function (err, data) {
        response.send("success" + data);
      });

    }
  });
  //获取微信access_token END

}

第四步:读取access\_token暴露给其他平台调用

新建个空白云函数,里面编写一下代码

function onRequest(request, response, modules) {//数据库对象    var db = modules.oData;
    //查询一条数据   db.findOne({
       "table":"WeiXin_access_token",
       "objectId":"NJEi333B"   },function(err,data){
        //JSON打印给客户端       response.send(data);
   });
}

这里是代码的执行结果,需要预览,可以打开一下链接。

http://cloud.bmob.cn/3fbee3a417249ddf/token

一样不到10行代码,即可暴露access\_token给其他平台调用。

总计不到20行代码,不需要10分钟,就可以实现微信整个access\_token的维护,与暴露给其他平台使用。最后还有一个关键问题, 2小时自动刷新access\_token

第四步:自动刷新access\_token
Bmob平台云函数支持liunx下面的crontab语法定时任务,当然国内其他公司的云函数也是支持定时任务的,具体看开发文档。

[http://doc.bmob.cn/cloud\_function/web/timing\_tasks/](http://doc.bmob.cn/cloud\_function/web/timing\_tasks/)

image.png

总结:
我们可以看到Serverless的Faas 开发微应用,开发效率比传统自己购买云主机,云数据库。高出很多倍。以至于国内这2年,阿里、腾讯、华为等云厂商都推出了自己的Faas 服务。大家都可以去体验一下,上线速度是否比自己购买的云主机更快,你只需要关系业务代码,不再需要去了解框架、运维、底层相关技术。

遇到问题核心调试技巧

调试网络是开发小程序核心技巧,把网络调试学会,能解决新手90%的问题,经常遇到大家说没取到数据,或者页面空白等。查看network 网络返回,刷新下页面,是否有数据,网络状态是多少,一般200是正常,400开头,500之类的错误是请求异常或服务器错误。

用户表没有自动新增用户

Bmob自动新增用户功能,是需要在后台应用配置,授权微信id,填写微信小程序AppSecret,才可拿到用户openid等信息。

电脑端可以预览手机端不显示数据

这个错误一般是合法域名的问题,查看他报的错误提示,把提示域名填写到微信。 如果是基于Bmob开发,则在Bmob应用配置里找到对应的合法域名填写到微信。 这里注意的是,修改了微信平台域名后重启下开发工具才会生效。

new Date跨平台兼容性问题

在Andriod使用new Date(“2018-01-01 00:00:00”) 没问题 ,在苹果端,是不支持这种格式,必须用 2018/01/01 00:00:00格式。可以使用js字符串替换,将短横替换为斜杠。var iosDate= date.replace(/-/g, '/');。

域名TLS错误

如果你确信自己域名没有错,一般来说,你重启下开发工具即可。

生成小程序二维码

这里需要注意的是微信有a、b、c方案,其中B方案二维码,需要大家的页面路径上线后才可生成。

wx.getUserInfo

2018年5月份,腾讯彻底废弃单纯使用js获取用户昵称头像等资料,必须使用页面按钮来让用户自己点击获取信息,如提示这个函数报错,请去掉相关代码。

小程序开发目前市场主要三种方案:

  1. 基于某个语言开发或者某款开源系统开发后端API接口
  2. 基于腾讯云官方方案
  3. 基于Baas 平台开发。

WordPress.png

1. 基于某个语言开发或者某款开源系统开发后端API接口

PHP领域很多人喜欢用discuz、WordPress等开源程序搭建小程序,他优点是如果你本身博客是基于这类系统,只需要开启API配置好https接口就可以基于此系统开发。

缺点也非常明显、移植性能差,出问题的几率高,并发低,安全相对比较低。前端新手上手困难等。

image.png

2. 腾讯云官方方案

优点:官方方案相对来说相关套件比较完善,懂前后端相关技术的人一键部署,基本在配置,然后一键上传,遇到几个小服务器问题,很快解决。
缺点:如果对整个后端不是很熟悉的人,就会比较麻烦。一个服务器问题部分人几天也解决不了,官方人员很难联系到效率低。例如下面这位开发者的遭遇
腾讯云小程序官方群.png

3. 基于Baas 平台开发

一、小程序Baas有什么用?

它可以免去小程序开发中服务器搭建、域名备案、https、API接口等,简单一句形容:专心写自己想要的页面就好了,其他Baas都帮你做好。

二、小程序你为何要使用BAAS ?

  1. 简单易用(由于封装了SDK,一行代码实现支付、客服消息不再是问题)
  2. 高效 (除了后端不用写代码、基础备案都免除了,可以想象效率)
  3. 低开发成本(降低开发与硬件基础设施的部署和维护成本。)
  4. 好维护(完全不用维护后端问题)
  5. 降低应用扩展(scaling)成本,当你有100W并发时会遇到性能瓶颈。目前老牌的BAAS平台如Bmob、AVcloud,都可以支持动态的自动扩张。

三、哪些企业使用了BAAS ?

相比小程序,在App行业早就赶上了Baas的快车,国内像华为、腾讯、知乎等知名企业都在使用Baas,华为、百度甚至对外推出过Baas产品,由于Baas产品对用户积累与服务要求比较高,目前听说华为的Baas只给内部项目使用,百度的Baas推出没多久由于内部问题关闭了。

4. 举个例子常规操作

想象一下,我们在一个小程序论坛,看到一份喜欢的源码,发觉还不错,下载源码,想发布上线审核。

传统上线例子:

PS:为了体现出传统也很快,这里暂且默认你公司有些积累之前一些准备工作都有,包含域名、备案、https、服务器、以及这套源码的运行环境。

第一步
把数据库导入到线上数据库。
第二步
把代码传到线上环境。
第三步
调试小程序代码。
第四步
提交上线审核

这里经常遇到的问题是很多小程序源码代码不全,只放了小程序源码,没有数据库相关信息。导入上去后代码与小程序之间有些认证机制,你可能要稍微阅读下代码,知道这套代码的实现原理(如果要进行修改,可能就需要知道这个后端系统的整个流程,由于没有文档,很多情况下是盲人摸象),进行调试发布上线。

Bmob后端云.png

小程序 Baas上线例子

下载源码后不需要配置,搭建,设置服务器,解析域名。 直接创建一个应用,发布上线。

第一步
Baas平台创建应用。
第二步
修改小程序appkey。
第三步
提交上线审核

这里每一步都相对简单,只要你发布过小程序,基本三分钟内能发布上线。即使应用个别数据表缺失也不是问题,比如没有留言表,或者反馈表。你只需要反馈页面反馈一下,系统会判断是否存在此表,如果不存在,则默认创建。

可以看出,在这种API接口模式开发的应用,使用Baas服务有绝对的优势,目前已有几千小程序开发者从腾讯转向Bmob移动后端云,将有更多的移动开发者加入到Baas的队伍中。

在项目上线后,可能会遇到一些人需要在线咨询,腾讯给予的解决方案是内置客服,一般可以分为2种使用方式。
  • 第一种内置在平台设置客服,在网页登陆客服处理消息
  • 第二种则是自己开发,微信会提供客服消息回调url,我们在此URl处理客服消息。

第一种微信平台使用方式

1. 微信控制台添加客服人员

image.png

2.使用方式

image.png

3.未处理消息会超时

超时的消息

  • 优点:无需任何开发,添加即可使用
  • 缺点:使用端被限制,经常要登陆查看消息,容易遗漏消息、容易出现超时。

第二种自有平台使用方式

注意事项

  • 服务端回调地址必须https
  • 2种方式只能2选1(启用并设置消息推送配置后,用户发给小程序的消息以及开发者需要的事件推送,都将被微信转发至该服务器地址中)

1. 设置回调服务器处理地址

此处使用Bmob 云逻辑功能,可以实现免服务器实现自己需要的服务端逻辑(比如支付回调,公众号回调,客服消息回调等等。。)

一、登陆 www.bmob.cn,点击应用>找到云逻辑

创建方法

创建方法.png

找到服务器调用URL地址

调用URL.png

填写到微信消息推送地址

image.png

写入微信回调验证代码

备注:微信公众号与小程序回调加密验证一直,我们可以直接复制公众号的验证代码,地址:https://docs.bmob.cn/cloudcode/WEB/d_cloudcodeweixin/doc/index.html#微信公众平台的开发,复制此页面代码

文档代码
image.png

复制到云函数

image.png

代码


function onRequest(request, response, modules) {
    var token = "weixin";         //这里的值必须与在微信公众号后台填入的token值一致
    var crypto = modules.oCrypto; //使用加解密模块
    var httptype = request.method; //获取调用云端逻辑的是post或者get方式
    var xml2js = modules.oXml2js; //实现xml和js格式之间的相互转换
    var db = modules.oData;         //数据库对象
    if ("GET" == httptype) {
         //是get方法,则是微信验证回调的url是否有效
          var oriStr = [token, request.query.timestamp, request.query.nonce].sort().join('')
          var code = crypto.createHash('sha1').update(oriStr).digest('hex');
          if (code == request.query.signature) { //验证通过,输出
              response.end(request.query.echostr);
          } else {
              response.end("Unauthorized");
          }
    } else {
           //是post,接收定阅者发送过来的消息后返回,把反馈意见存储表“message”中,或做一些其他操作都可以。
         


    }
}

这里的 else 可以做的事情可多了,例如:

  • 发送个短信或邮件给你的客服人员,告知有人来问什么问题了,客服人员觉得重要可以回复,不重要可以忽略。
  • 实现与用户交互(例如回复1.话费问题 回复2.流量问题。。。)
  • 接入第三方只能聊天助手,例如小娜这种。
  • 实现自动回复,第一次提示XXX欢迎你咨询本小程序,第二提醒你反馈的信息已经收到。
  • 写入到数据表,再小程序端查出来,实现最新微信官方小程序:公众平台助手一样的功能。直接手机回复客服消息
  • 等等。。。

文档有提供写入数据表代码

//是post,接收定阅者发送过来的消息后返回,把反馈意见存储表“message”中。
            db.insert({
              "table":"message",             //表名
              "data":{"userId":request.body.xml.FromUserName,"content":request.body.xml.Content}           
            },function(err,data){    
           //写入数据库成功处理代码                 
                         });

比如我这实现个简单例子

image.png

公开免费接口实现微信消息主动推送
image.png


image.png

云逻辑里面调用另外一个云逻辑代码

文档地址
https://docs.bmob.cn/cloudcode/WEB/b_developdoc/doc/index.html#云端逻辑对象
var functions = modules.oFunctions;
functions.run({
               "name": "reply",
               "data":{"userId":request.body.xml.FromUserName,"content":content}
            },function(err,data){
               //回调函数
               if(request.body.xml.Content!=undefined){
                   functions.run({
                       "name": "sendMaster",
                       "data":{"userId":request.body.xml.FromUserName,"content":request.body.xml.Content}
                    },function(err,data){
                       //回调函数
                       
                    });    
               }
            });    

主动发送消息代码

//云端逻辑方法名:reply

function onRequest(request, response, modules) {

        var content = request.body.content || '你好。';
        var userId = request.body.userId || 'ocBzs0I9fkcJ6kq1_xSxtN5dj7bI';
    
        //获取Http模块
        var http = modules.oHttp;
        
        var options = {
          "url": 'https://api.bmob.cn/1/wechatApp/getAccessToken',
          "headers": {
            "x-bmob-application-id": "xx",
                    "x-bmob-rest-api-key": "xx",
            'Content-Type': 'application/json'
          }
        };
        http.get(options, function(error, res, body) {
            var result = JSON.parse(body)
            // response.send(result.access_token);
            
            
             /**
            *主动发起消息给用户请求
            */
            //获取Http模块
            var http = modules.oHttp;
            
            var options = {
              "url": 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='+result.access_token,
              "body":JSON.stringify({"touser":userId,"msgtype":"text","text":{"content":content}})
            };
            // response.end(options.url);
            http.post(options, function(error, res, body) {
                console.log(body);
                response.send(body);
            });
        });
        
       
}                                                                                    

总结

前面截图指的微信回调地址选json Bug的问题是返回的头部不符合http标准。返回json格式header头应该是Content-Type:application/json,而微信的选json还是Content-Type:text/xml,如果将来微信改正过来,则支持选json格式。
无服务函数已经越来越受开发者欢迎,无需购买主机,搭建环境。不到10行代码,实现微信服务器返回回调授权。这是未来微型服务端的发展方向在线编程。腾讯云的无服务函数也已经公侧,个人测式暂时还是Bmob的功能实用很多。

无服务函数.png