资讯专栏INFORMATION COLUMN

如何根据protobuf来Mock后台返回的数据

shmily / 662人阅读

摘要:简称是公司内部的混合语言数据标准,他们用于系统和持续数据存储系统。可用于通讯协议数据存储等领域的语言无关平台无关可扩展的序列化结构数据格式。我们想要的结果是最终的返回的数据。如果当前开发开启,就回直接返回数据。数据是与同级的文件。

Protobuf

Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,他们用于 RPC 系统和持续数据存储系统。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。为什么要讲到它,因为我们后台的协议就是用的它。

Mock

Mock也可以叫mock object,模拟对象,在面向对象程序设计中,以可控的方式模拟真实对象行为的假对象。前端比较有名的库是Mock.js。

为什么要mock呢?
1、前后端分离,并行开发,能够充分利用人力,避免等待。
2、可以丰富测试用例,提前模拟很多的真实场景数据,而不必等到线上环境才发现问题。

但Mock.js有个问题:学习和配置成本高。

// 配置 Mock 路径
require.config({
    paths: {
        mock: "http://mockjs.com/dist/mock"
    }
})
// 加载 Mock
require(["mock"], function(Mock){
    // 使用 Mock
    var data = Mock.mock({
        "list|1-10": [{
            "id|+1": 1
        }]
    })
    // 输出结果
    document.body.innerHTML +=
        "
" +
        JSON.stringify(data, null, 4) +
        "
" }) // ==> { "list": [ { "id": 1 }, { "id": 2 }, { "id": 3 } ] }

用它之前必须要先配置一个Ajax的请求路径,然后根据后台的协议,学习mock的语法,才能模拟出list这个数组。所以这里存在着两个问题:
1、配置成本和语法学习成本
2、后台协议转换为mock语法

很多时候,等到我们开发完业务逻辑,已经没有多少耐心来写这个mock逻辑,简单的协议还好,如果涉及到很复杂的,写这个mock的逻辑就更加不愿意。

为了帮前端同学偷个懒,有必要把这个过程给省了。

Protobuf转换为JSON

git上已经有针对Protobuf开源的js接口:https://github.com/dcodeIO/pr...。因为构建工具我们使用的是gulp,同样的也有个对应的插件:gulp-protobufjs,但是没法拿来就用。

首页我们来看下这个gulp-protobufjs插件所做的事情

var gulp = require("gulp");
var gulpprotobuf = require("gulp-protobufjs");
 
gulp.task("default", function () {
  return gulp.src("file.proto")
    .pipe(gulpprotobuf())
    .pipe(gulp.dest("out/"));
});

读取proto文件,然后生成一个文件,文件类型可以自定义。
如果产出的是.js文件,那么结果是commonjs模块文件:

module.exports = require("protobufjs").newBuilder({})["import"]({
    "package": "mmgameweappwap",
    "syntax": "proto2",
    "messages": [
        {
            "name": "User",
            "syntax": "proto2",
            "fields": [
                {
……

如果是.json文件:

{
    "package": "mmgameweappwap",
    "syntax": "proto2",
    "messages": [
        {
            "name": "UserItem",
            "syntax": "proto2",
            "fields": [
                {
                    "rule": "required",
                    "type": "string",
                    "name": "user_id",
                    "id": 1
                },
                {
                    "rule": "optional",
                    "type": "string",
                    "name": "head_img_url",
                    "id": 2
                },
                {
                    "rule": "optional",
                    "type": "string",
                    "name": "nick_name",
                    "id": 3
                }
            ]
        },
……

很显然,这不是我们想要的最终结果。我们想要的结果是最终的ajax返回的数据。当然有了协议的json结构,字段类型、字段名也都有了,剩下的事情就只需根据他们mock一些数据。这个json文件可以理解为对接口的一个描述文件。

pb协议的rule常见的有以下几种:

optional:可选

required:必须

repeated:数组

数据类型,有以下几种最基本的类型,基本都可以映射为js常用的数据类型。

例子

在解析pb文件的时候,后台CGI接口名会被定义为message。

package mmgameweappwap;
message GetDiceGameRoomRequest {
    required string room_id = 1;
}
message GetDiceGameRoomResponse {
    required int32 errcode = 1;
    required string errmsg = 2;

    optional OkResult data = 3;
    message OkResult {
        repeated UserDiceItem user_dice_list     = 1;
        required uint32 room_close_remain_second = 2;
        required bool room_closed                = 3;
    }
}

package 可以理解为模块,上文我们定义了一个mmgameweappwap模块。

GetDiceGameRoomRequest:请求的message

GetDiceGameRoomResponse:返回的message

GetDiceGameRoom:接口名称

一个CGI接口在pb协议中的定义一般会成对的出现。RequestResponse是所有接口标准的后缀,以区别普通的message。依赖这种规则,就可以把接口解析出来,并且也能够知道其请求、返回的message。

从上面的pb协议看,message可以被嵌套,OkResult是属于GetDiceGameRoomResponse子message。同一个pb文件下,message名可能重复,整个协议可以看成是一颗树。如果要找对应的message,必须从当前节点的子节点开始查找,否则可能找错。

处理的流程比较简单。如下图所示:

通过分析知道接口名后,如果前端的请求都是统一的,就可以通过请求接口的代码模板生成请求代码。生成对应的API.js:

var Promise = require("js/libs/Promise");
var Util    = require("js/common/util");
var Mock = require("./mock");
var app     = getApp();

var FETCH_URL   = "http://xxxxx/gameweappwap/";
module.exports = {
   getDiceGameRoom: function(data) {
        return new Promise((resolve, reject) => {
            if(app.mock){
                resolve(Mock.getDiceGameRoom);
                return;
            }
            app.request({
                url: FETCH_URL + "getsmobapremadeinfo",
                data: {
                    room_id: data.room_id, // string 
                },
                method: "POST",
                header: {
                    "content-type": "application/json"
                },
                success: resolve,
                fail: reject,
……

exports对外的接口就是CGI的接口名:getDiceGameRoom。
request中的roomid就是从pb协议中解析出来的,后面的注释标注了其类型。这样一个ajax请求就非常的简单明了了。开发者只需要API.getDiceGameRoom调用即可。如果当前app.mock开发开启,就回直接返回mock数据。mock数据是与API.js同级的文件。

这里的数据都是调用mock.js生成的,当然我们可以加入一些业务的数据,这样测试起来更加真实。

运用场景

1、前端安全,模拟xss例子。

随机生成一些xss用例,用于前端页面的测试。

2、前端UI测试。

在实际工作中,经常会遇到文本截断的问题。UI界面在多行文本的情况下会不会表现正常这个问题,在这种情况下就可以轻易的测试出来,而不需每次叫后台开发配合加一些假数据。

如下图,我们可以针对字符串类型的数据生成一些长文本。

结语

所有的项目都在统一框架下,每个项目都保持统一的目录结构,只需要自定义一些配置就能初始化项目脚手架,剩下的只需要专注于业务开发。

by addy 原创文章,欢迎转载,但希望全文转载,注明本文地址。http://www.iamaddy.net/2017/0...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85001.html

相关文章

  • 基于 HTTP 请求拦截,快速解决跨域和代理 Mock

    摘要:今天这篇文章,我们会介绍几种常见的方法和其中存在的问题,并提出如何基于请求拦截,快速解决跨域和代理问题的方案。因为没有修改该请求,只是延迟发送,这样就保持了原请求与业务服务器之间的所有鉴权等相关信息,由此解决了跨域访问无法携带的问题。 近几年,随着 Web 开发逐渐成熟,前后端分离的架构设计越来越被众多开发者认可,使得前端和后端可以专注各自的职能,降低沟通成本,提高开发效率。 在前后端...

    dreamGong 评论0 收藏0
  • 基于http协议使用protobuf进行前后端交互

    摘要:呵呵呵打印出来的是二进制流需要进行化然后给前端。不然的话浏览器会自动解析成文字的前端需要进行接受二进制流先引入文件以及插件前端用请求的路由,在回调函数里的为后端的返回值。 protobuf介绍 由于网上关于protobuf的交互的资料比较零散,所以自己整理了一下关于protobuf前后端交互的资料,以作参考。 Google Protocol Buffers 简称 Protobuf,它提...

    hersion 评论0 收藏0
  • .NET Protobuf包装器库

    摘要:不然将根据属性名称进行排序。获取包装器获取包装器我们可以直接转换模型对象为。所有与对象不能包含值。它们将作为类型进行序列化。我们定义了一个抽象类。使用会获得最佳性能。许可证许可证库使用许可证。Wodsoft Protobuf Wrapper内容关于需求安装用法序列化反序列化字段定义字段排序非空构造函数对象获取Protobuf包装器高级支持的属性类型与Protobuf类型的关系如何工作性能许可...

    Carl 评论0 收藏0

发表评论

0条评论

shmily

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<