一、什么是前后端分离?

前后端分离的概念和优势在这里不再赘述,有兴趣的同学可以看各个前辈们一系列总结和讨论:

尤其是《前后端分离的思考与实践》系列文章非常全面的阐述了前后端分离的意义和技术实现。如果不想看上面的文章,可以在脑海里留下这样一个轮廓就好:

本文主要阐述趣店团队基于Koajs的前后端分离实践方案。

二、为什么选择koa?

koa是由Express 原班人马打造的一个更小、更健壮、更富有表现力的 Web 框架。(koa官网需用梯子,中文文档可以参考郭宇大神的翻译:koa中文文档,这里也不详细介绍。)

看到koa之后,简单看了下文档和源码,立刻感觉koa不就是为前后端分离而诞生的轻量级框架吗?

因为:

  • 如果要用koa实现一整套类似于PHP的Laravel或者Ruby on Rails的服务端MVC框架其实还有很长的路要走;

  • koa中间件的思路可以很好的被前后端分离的思路利用起来,比如:路由、模板引擎、数据代理等等;

  • koa基于ES6的generator特性(不了解generator的同学可以参考阮一峰老师的文章),利用co等模块让前端同学写一个路由再简单不过;

  • ……

总之,koa给我的第一印象就是:如果用它来实现一套前后端分离的框架,非常高效轻量易扩展

三、如何实践?

1、刀耕火种的年代

在谈如何实现基于koajs的前后端分离框架的之前,必须提一下在做分离之前趣店(原趣分期)的情况:

  • 一个仓储托管了趣分期业务前后端所有代码,由于不断维护,这个仓储足足有600M

  • 后端为了满足NativeAPP的接口需求,这个600M的仓储还包含了提供给客户端的代码

  • 前后端开发流程为:先由后端写一个路由 → 前端将这个路由写成可以交互的页面 → 前端提交代码后后端同学“套模板”填充数据

  • 前后端开发都在一台远程开发机上,通过samba隐射到本地进行开发;

  • 前端几乎没有做任何打包编译;有时候为了偷懒,甚至把CSS和JS直接以内嵌的方式写在模板里(不要去联想vue,两码事儿)

写到这儿想贴代码来着,想想还是算了……

2、基于koa的实现

无论使用什么工具要实现前后端分离框架,无非要满足这样几点:

  • 更便捷地创建路由

  • 更高效地代理数据请求

  • 更灵活地环境部署

先看一个已经实现了demo应用的目录结构:

.
└── demo
├── controller
│ ├── data.js
│ ├── defaultCtrl.js
│ └── home.js
├── static
│ ├── css
│ ├── image
│ └── js
└── views
└── home.html

这个结构大家再熟悉不过:controller提供路由;static包含静态文件;views提供模板文件。
这里可能大家会有疑问,如果我的前端构建是components的模式怎么办呢?

├──components_a
│ ├── home.js
│ ├── home.css
│ └── home.html
├──components_b
...

没关系,do what u want!很多boilerplate可以直接拿到这个框架下直接使用,我们团队自己也正在使用了requirejs和vue的构建方案。

1. 更便捷地创建路由:controller

回到上文提到的案例:

controller
├── data.js
└── home.js

这段代码生成的是一个/data/*,/home/*路由,用过Express的同学对这种路由实现肯定一点都不陌生。

但有一点不一样的是,koa下面每一个路由是一个独立的generator函数(很遗憾,generator函数不能使用箭头函数的语法来表示),参看controller/home.js

exports.index = function* () {
yield this.bindDefault();
yield this.render('home', {
title: 'Hello , Grace!'
});
}

你还可以用一个对象把一个controller包起来,,参看controller/data.js

exports.info = {
repo: function*(){
yield this.proxy('github:repos/xiongwilee/koa-grace')
}
}

这种写法非常适用于仅仅用来做一个数据代理的ajax请求的控制器。当然,如果需要的话,你还可以在控制器里对数据做一些加工。

另外,还有几个细节与express的路由控制器不太一样:

  1. 终止请求的动作都有koa来完成,在这里的controller里,你不需要通过res.end()来终止请求;

  2. 这里的controller的作用域,就是koa的上下文,所以你可以通过this.req获取request对象;

  3. 这里的controller里,异步回调的语法成为了往事,请尽情的使用yield

我们对现在的路由方式做了一个压测:8核CPU/8G内存的机器,通过一个路由返回hello world!,结果显示:8核CPU/8G至少能扛住1000QPS的压力(cpu idle不到60%,cpu load接近8)。

2. 更高效地代理数据请求:proxy

前后端分离模式下的,数据代理主要有这两种使命:

  • 一种是,拼装一个和多个数据结果,给模板渲染数据或者给Ajax接口

  • 另外一种是,接受用户的数据请求,将结果交给一个后端接口

第一种场景,比如:一个用户中心的页面,需要展示用户的用户信息、订单列表、喜欢的商品推荐等等信息。由于后端的架构,用户、订单、商品可能都是属于不同的服务,这就意味着,后端同学需要给你同时拼装这么多数据,拼装还有可能是同步获取每个接口然后再一起返回给前端。

现在,就可以尽情的发挥nodejs异步并发及koa的generator同步语法的优势,我们还可以这么写:

 repo: function*(){
yield this.proxy({
data1:'github:repos/xiongwilee/data1',
data2:'github:repos/xiongwilee/data2',
data3:'github:repos/xiongwilee/data3'
})
}

koa会自动并发请求所有接口,然后将结果返回给你,然后可以在上下文的backData中获取结果集。

另外一种场景,比如用户需要上传一张图片或者提交一篇文章,你也可以这样写:

submit: function*(){
yield this.proxy('http://test.com/submit')
}

不用做任何配置,koa会直接把request数据buffer直接通过管道pipe给后端接口。

值得一提的是:

  • 有没有发现,这种proxy方式是没有同域机制的限制 了,前端面试常问的跨域方案都不是事儿;

  • 另外,同学们可能觉得,本来一个请求都能搞定的事情非要用nodejs代理一次,会不会很慢?事实上,我们的测试结果显示:内网访问的情况下,nodejs代理耗时不超过10ms

最后,我们也做了一个压测:8核CPU/8G内存的机器,通过一个路由将请求代理到另外一个接口,结果显示:8核CPU/8G至少能扛住300QPS的压力,这个结果比纯路由的压测情况要低很多,值得注意。

不过有意思的一点是,我们压测发现:proxy的性能与接口响应时间无关,与接口响应content大小有密切关系:接口响应内容越大,proxy性能越差

3. 更灵活地环境部署

基于koa可以实现各类有意思的中间件。比如:可以拦截请求计算请求总耗时中间件、可以匹配路径实现本地的静态文件服务器、可以不需要再另开server实现一个mock数据的功能……

a) 开发环境

上文提到过一个DEMO的文件目录,具体在开发环境和生产环境中整体目录结构中其实是这样的:

├── app                // 开发模式下应用模块目录
│ ├── blog
│ └── demo
├── cli // 配套命令行工具
│ ├── bin
│ ├── lib
│ └── package.json
├── log // 日志目录
└── server // 服务器目录
├── app // 实际服务端引用的模块目录
│ ├── blog
│ └── demo
├── bin
├── config
├── src
└── package.json

在开发环境下,你可以将./app下的项目源文件直接编译到./server/app目录,这就意味着:./app/目录下的各个项目,你自己想怎么玩就怎么玩

我们目前有基于gulp+requirejs的模块化方案和基于webpack+vue的前端构建方案,其中gulp+requirejs的方案已经开源:https://github.com/xiongwilee... 。

基于上文提到的路由和数据代理的功能,现在我们的开发模式就可以优化为:前后端确定接口→前后端同时开发→联调提测上线。给开发带来的好处自不必说:

  • 后端接口完全解耦,前端利用异步并发,性能可以达到最优;

  • WebAPP和NativeAPP可以通用一套接口,后端省了不少成本;

  • 前后端独立之后,前端构建的成本更低,灵活性更高;

  • ……

b) 生产环境

生产环境的部署与大多数服务部署类似:经过SLB之后到nginx进行反向代理,走到nodejs服务响应请求;可以在nginx层进行负载均衡和监控;如果需要用到缓存,可以在nginx和nodejs之间再加一层Varnish

这里必须要推荐下最牛哔的nodejs进程管理工具:pm2,完成了趣店生产环境下nodejs进程管理和nodejs日志切分。

然后提一下,我们的沙盒环境和测试环境部署。

沙盒只需要摘一台性能比较low的线上机器,提供给办公网络访问就行。因为数据代理的接口直接走的服务端对应环境的接口,整个沙盒环境和测试环境的搭建也非常愉快。

另外,我们对线上业务做了一个压测:单台8核CPU/8G机器,能扛住500QPS左右的压力

最后,关于环境部署,再提两个场景:

  • 一个场景是,超越前后端分离框架的本职工作,实现团队文档系统

因为前后端分离框架本身是不支持数据库和SESSION存储功能的,为了满足一些简单的数据库和文件上传需求,我们自己实现了两个中间件,一个能够利用mongoose很简单地与mongo打交道,一个利用formidable,koa-send模块轻易实现文件上传和下载;从而很快实现了团队博客和文档系统。

当然了,这个文档系统和团队博客仅限在内网系统中使用。

  • 另外一场景是,后端环境使用Java MVC框架下的前后端独立开发

我们团队与蚂蚁金服团队深度合作(事实上是作为TP,实现支付宝下的业务需求),必须使用蚂蚁金服的基于Java的sofalite MVC框架,而且坑爹的是:蚂蚁金服不能提供他们的前端构建框架!

这就意味着:我们团队的前端同学需要回到刀耕火种时代,跟后端同学用一个仓储自己搭建Java环境进行本地开发了。

但是,别忘了,我们现在有基于koa的前后端分离框架啊(知乎腔)!

事实上,前后端独立开发的唯一瓶颈就在与Java的velocity模板引擎;而我们的前后端分离框架的模板引擎是可配的。

所以,前后端定好了接口,然后前端就愉快地用上mock数据独立开发去了;最后,整个项目提前四天开发联调完成

四、koa-grace

主(guang)角(gao)终于要出场了!

这套前后端分离框架——koa-grace:基于koa的前后端分离框架已经开源。欢迎各路大神star/fork/提ISSUE,谢谢!!!

另外,配套命令行工具暂时仅限内网使用,后续会开源出来。最后,关于koa-garce还得啰嗦两点:

1)koa-grace是基于koa 1.x版本

目前koa-grace所有的中间件都是基于koa 1.x,而koa 2.x正式发布之后会立刻跟进。

但koa-grace毕竟只是一个轻量级的框架:Requiring babel to run your server is just not good developer experience.(引自:koa/issues/533)。

2)koa-grace需要完善测试用例

vue的作者尤雨溪说过,不写测试的开源项目不是合格的开源项目。而koa-grace目前还没有测试用例覆盖,希望大家一起来完善。

最后

无论前端怎么玩、无论技术怎么发展,任何架构最终都是为了服务于产品

基于 koajs 的前后端分离实践的更多相关文章

  1. [转] 基于NodeJS的前后端分离的思考与实践(五)多终端适配

    前言 近年来各站点基于 Web 的多终端适配进行得如火如荼,行业间也发展出依赖各种技术的解决方案.有如基于浏览器原生 CSS3 Media Query 的响应式设计.基于云端智能重排的「云适配」方案等 ...

  2. (转)也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

    原文链接:http://ued.taobao.org/blog/2014/04/full-stack-development-with-nodejs/ 随着不同终端(pad/mobile/pc)的兴起 ...

  3. 也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

    前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们重新思考了“前后端”的定义,引入前端同学都熟悉的NodeJS,试图 ...

  4. 基于NodeJS的全栈式开发(基于NodeJS的前后端分离)

    也谈基于NodeJS的全栈式开发(基于NodeJS的前后端分离) 前言 为了解决传统Web开发模式带来的各种问题,我们进行了许多尝试,但由于前/后端的物理鸿沟,尝试的方案都大同小异.痛定思痛,今天我们 ...

  5. 基于NodeJS进行前后端分离

    1.什么是前后端分离 传统的SPA模式:所有用到的展现数据都是后端通过异步接口(AJAX/JSONP)的方式提供的,前端只管展现. 从某种意义上来说,SPA确实做到了前后端分离,但这种方式存在两个问题 ...

  6. 【SpringSecurity系列2】基于SpringSecurity实现前后端分离无状态Rest API的权限控制原理分析

    源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/01-springsecurity-state ...

  7. 基于Vue的前后端分离项目实践

    一.为什么需要前后端分离 1.1什么是前后端分离  前后端分离这个词刚在毕业(15年)那会就听说过,但是直到17年前都没有接触过前后端分离的项目.怎么理解前后端分离?直观的感觉就是前后端分开去做,即功 ...

  8. [原创]基于VueJs的前后端分离框架搭建之完全攻略

    首先请原谅本文标题取的有点大,但并非为了哗众取宠.本文取这个标题主要有3个原因,这也是写作本文的初衷: (1)目前国内几乎搜索不到全面讲解如何搭建前后端分离框架的文章,讲前后端分离框架思想的就更少了, ...

  9. Jeecg-Boot 2.0 版本发布,基于Springboot+Vue 前后端分离快速开发平台

    目录 Jeecg-Boot项目简介 源码下载 升级日志 Issues解决 v1.1升级到v2.0不兼容地方 系统截图 Jeecg-Boot项目简介 Jeecg-boot 是一款基于代码生成器的智能开发 ...

随机推荐

  1. 使用WeCloud消息推送接口发送消息NodeJs版

    WeCloud是一家初创公司的产品,眼下主要在做Android和IOS消息推送这块.他们提供了用于向设备发送消息的协议,详细协议内容见消息推送协议. 这篇文章将使用NodeJs基于这个推送协议完毕向A ...

  2. stagefright omx小结

    由于stagefright和openmax运行在两个不同的进程上,所以他们之间的通讯要经过Binder进行处理,本小结不考虑音频这一块,假设视频为MP4封装的AVC编码文件. 先简单的看一下stage ...

  3. Transform 1

    Transform字面上就是变形,改变的意思.在CSS3中transform主要包括以下几种:旋转rotate.扭曲skew.缩放scale和移动translate以及矩阵变形matrix.下面我们一 ...

  4. Code Complete阅读笔记(一)

    代码大全也读了好几个月了,一开始读中文版,到现在慢慢尝试着读原版,确实感受到了"每天进步一点点"的魅力.遗憾的是没有从一开始就做阅读记录,总有不能尽兴和思路不清之感.确实,就像项目 ...

  5. sqlserver2008 中使用MSXML2.ServerXMLHttp拼装soap调用webservice

    要调用的接口方法:UP_ACC_inst_Info(string xml) 接口参数:xml格式的字符串 接口功能:传递人员编号.备注到接口进行更新,接口返回更新结果. 实例: declare @st ...

  6. C#索引器:在集合或数组中取出某一个元素 举例 _【转】

    Garmmar: [访问修饰符] 数据类型 this[参数列表] { get { 获取索引器的内容 } set { 设置索引器的内容 } } Eg: <span style="font ...

  7. c#程序为PDF文件填写表单内容

    众所周知,PDF文件一般情况下是无法修改的,如果你有一张现成的PDF表格,这时想通过编程实现从数据库或者动态生成内容去填写这张表格,就会有些问题了,首先我们要解决以下2个重要的问题: 1.如何将内容写 ...

  8. Hibernate常见接口说明

    (一)SessionFactory 1. getCurrentSession()和openSession()区别 getCurrentSession创建的session会和绑定到当前线程,而openS ...

  9. (转) eclipse debug (调试) 学习心得

    1.Step Into (also F5) 跳入2.Step Over (also F6) 跳过3.Step Return (also F7) 执行完当前method,然后return跳出此metho ...

  10. shell中的expr命令

    expr 可以进行的操作如下: 逻辑操作 arg1 | arg2 逻辑或操作,真则返回arg1,否则返回arg2(以null或者0来判断参数的真假,有短路功能) arg1 & arg2 逻辑与 ...