Fork me on GitHub

从NodeJS搭建中间层再谈前后端分离

前言

  • 后端出于性能和别的原因,提供的接口所返回的数据格式也许不太适合前端直接使用,前端所需的排序功能筛选功能,以及到了视图层的页面展现,也许都需要对接口所提供的数据进行二次处理
  • 这些处理虽可以放在前端来进行,但也许数据量一大便会浪费浏览器性能。因而现今,增加node端便是一种良好的解决方案。
  • 下面关于微信小程序demo的server端代码中,通过http模块对真实后台(网易云音乐API)发起http请求,然后通过express模块搭建后端服务。
  • 发起请求:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // http.js
    var formatURL = require('./formatURL.js');
    var http = require('http');
    const POSThttp = function(request){
    return new Promise((resolve, reject) => {
    let body = '';
    // http模块拿到真实后台api的数据
    http.get(formatURL(request.body.musicname), function(res){
    res.on('data', (data) => {
    body += data;
    }).on('end', () => {
    // 格式化
    const {
    name,
    audio: musicUrl,
    page,
    album: {
    name: musicName,
    picUrl,
    },
    artists: [{
    name: singer,
    }],
    } = JSON.parse(body).result.songs[0];
    const reply = {
    name,
    picUrl,
    musicUrl,
    page,
    singer,
    };
    resolve(reply);
    });
    });
    };
    module.exports = POSThttp;
  • 得到数据传回前端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var express = require('express');
    var POSThttp = require('./POSThttp.js');
    var bodyParser = require('body-parser');
    // 使用body-parser解析post请求的参数,如果没有,req.body为undefined。
    var app = express();
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
    extended: true
    }));
    app.post('/', (req, res) => {
    POSThttp(req).then((data) => {
    res.send(data);
    }).catch((err) => {
    res.send(err);
    });
    });
    app.listen(3000, () => {
    console.log('open wx-audio server successful!')
    });
  • 上面的几十行代码也就实现了一个简单的中间层的demo,并做到了在中间层格式化参数便于前端进行使用的过程。

为什么需要中间层?

  • 其实这个问题,我认为跟面试常考的题:“为什么需要前后端分离?”是类似的,现今大公司的老项目(包括百度、搜狐等公司所采用的后端渲染等),或多或少都会存在这样的一些问题:
    • 前端代码越来越复杂
    • 前后端依旧高度耦合
    • 无法良好的支持跨终端

前辈们提出的解决方案

  • 前端代码越来越复杂,我们希望尽可能地减少工作量,开始使用类似MV*的分层结构,使前端后分离成为必要。
  • 前端需要处理更多的工作,希望有权操控ViewRouter(如:SPA的尝试)
  • 各种终端设备的兴起,需要我们把页面适配到更多的地方
  • 开始:我们所尝试的CLIENT-SIDE MV* 框架后端暴露数据接口、处理业务逻辑,前端接收数据、处理渲染逻辑。
关于MVC的定义:
MVC是一种设计模式,它将应用划分为3个部分:数据(模型)、展现层(视图)和用户交互(控制器)。换句话说,一个事件的发生是这样的过程:
  1. 用户和应用产生交互。
  2. 控制器的事件处理器被触发。
  3. 控制器从模型中请求数据,并将其交给视图。
  4. 视图将数据呈现给用户。
我们不用类库或框架就可以实现这种MVC架构模式。关键是要将MVC的每部分按照职责进行划分,将代码清晰地分割为若干部分,并保持良好的解耦。这样可以对每个部分进行独立开发、测试和维护。
  • 如:BackboneEmberJSKnockoutJSAngularJS等框架。
  • 但这样的方式仍旧存在问题:
各层职责重叠
  • Client-side Model 是 Server-side Model 的加工
  • Client-side View 跟 Server-side是 不同层次的东西
  • Client-side的Controller 跟 Sever-side的Controller 各搞各的
  • Client-side的Route 但是 Server-side 可能没有
性能问题
  • 渲染,取值都在客户端进行,有性能的问题
  • 需要等待资源到齐才能进行,会有短暂白屏与闪动
  • 在移动设备低速网路的体验奇差无比
重用问题
  • 模板无法重用,造成维护上的麻烦与不一致
  • 逻辑无法重用,前端的校验后端仍须再做一次
  • 路由无法重用,前端的路由在后端未必存在
跨终端问题
  • 业务太靠前,导致不同端重复实现
  • 逻辑太靠前,造成维护上的不易
渲染都在客户端,模板无法重用,SEO实现麻烦

NodeJS作为中间层的全栈开发方案

  • 参考淘宝前后端分离解决方案中的一张图:
    淘宝前后端分离解决方案配图
  • 有了NodeJS之后,前端可以更加专注于视图层,而让更多的数据逻辑放在Node层处理
  • 除了上图列举的作用,我们使用Node层还可以有下面的好处:
    • 渲染页面,体验优化
    • 中间层带来的性能问题,在异步ajax转成同步渲染过程中得到平衡
  • NodeJS对于数据的运算、逻辑处理数据库的操作不如java方便、快捷、稳定,因此,将NodeJS作为中间层,从底层java获取数据、对数据做简单的处理后返回给客户端。
  • 对于前端来说,NodeJS的学习成本是相当低的:我们无需学习一门新的语言,就能做到以前开发帮我们做的事情,一切都显得那么自然。
------ 本文结束 ------