前后端分离架构中的接口设计

前后端分离一般是指在软件开发过程中,前端代码和后端代码分别开发,互不干涉,不使用后端语言去写前端,也不用前端技术写后端,从形式上来说,一般是不用JSP或PHP混写代码,但并不是说不能用JSP或PHP文件格式。前后端分离后,前后端的通信一般是通过HTTP接口的方式进行调用。
对与前后端分离的概念有很多人都会有误解:

  • 前后端分离就不能使用JSP这样的文件:
  • 实际上分离并不一定非得用HTML文件,只要不在JSP写大量后端代码,那么JSP只是一种文件后缀而已,它是经过javac预编译的,需要在web容器里把编译好的.class转成html文档返回给浏览器,对浏览器来说,拿到的依然是html文档,只不过对于前后端分离的部署方式来说不太方便而已,但绝不是说.jsp文件就不是前后端分离了,比如我们可以用jsp来获取项目的basePath,而前端在发送http请求时就可以知道接口的全路径了。举个例子:如果在项目的/app/modules/users/index.html中发送了一个ajax请求:
$.ajax("getUserList?page=1&limit=20",...)

这样发出的请求地址是:

http://serverName:port/projectName/app/modules/users/getUserList&page=1&limit=20

这样很容易有一个404错误,因为实际上我们的接口路径是:

http://serverName:port/projectName/getUserList&page=1&limit=20

那么如果我们用绝对路径呢?

$.ajax("/getUserList?page=1&limit=20",...)

如果你的项目部署在tomcat的根目录里(通常是ROOT),那是没问题,否则的话,实际的请求变成了:

http://serverName:port/getUserList&page=1&limit=20

这个绝对路径是相对于tomcat来说了,省略了项目名称,如果你不是部置在tomcat根目录里,仍然会得到一个404错误,这里我们需要配置上项目名称:

$.ajax("/projectName/getUserList?page=1&limit=20",...)

这样是没问题了,但如果项目中很多ajax请求,在每个地方都要带上这个项目名称,一旦有一天,运维告诉你项目部署的projectName改了(有时可能不得不这么做),那前端工程师的苦逼日子就来了。
对于单页面应用还好,可以做一个全局的配置来保存这个projectName,这样,如果有改动也只是改一个地方而已,但对于多页面应用来说,不可能每个页面都定义一个JS全局变量,但我们可以借助JAVA的能力,使用JSP里的方法把这个变量动态地写在页面里:

<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<script type="text/javascript" >
var basePath="<%=basePath%>";
</script>

当然要解决这个问题也还有其他办法。但这么做我觉得并不违反前端后分离架构,因为在运行期前端代码和后端代码仍然是分开的。在JSP里并没有使用struts的标签库,也没有调用java方法取得数据后生成HTML,数据仍是加载后异步取的。

  • 前后端分离cookie,session就没用了

之所以有这个误解,可能是以为ajax请求会与session没有关系了,实际上session是管理的会话,只要是同一个会话里的http请求,不管是请求一个页面,还是ajax请求个接口,只要是同源并在同一会话,都是属于一个session里的,ajax请求到后端后,仍然可以从HttpRequest里拿到session里面的信息。
- 前后端分离就是前端只管前端的事,后端只管后端的事,互不干涉
这句话不算错,但也不是绝对,在一个项目里,团队里的如果做了前后端的分工,就要配合好去做项目,也许对于全栈工程师来说前后端可以一起搞定,但对于前后端分离的架构来说,同一个功能则需要前端工程师和后端工程师鼎力配合才可完成,分离的好处是为了让大家专注于做自己擅长的事,是为了让前端体验更好后端架构更稳定,让前端和后端的工程师都有更多精力做更多的测试,让前端心里想着页面,后端想着逻辑,数据库则做好存储,没有好的配合,只想撇清责任,那么分还不如不分。
- *前后端分离就不能用模板技术了
对于模板技术来说有后端模板如freemarker和前端模板技术如jade,无论哪种模板,都是为了生成html的,模板是为了把结构抽取出来,让数据去匹配模板,达到复用的目的,后端模板需要经过编译,而前端模板则直接返回就可以了,那么是不是使用了后端模板技术就不是前后端分离了吗?
这个和使用jsp还不一样,实际上如果使用后端模板就类似于在jsp里写一些html输出的代码,但写起来又不一样,因为模板技术框架一般做了封装,使得你的数据和模板是分开的,只是在需要的时候才合在一起,而不像jsp里java与html混写的方式,一般情况下,为了页面体验,即使使用后端模板技术,模板文件也常是前端工程师或全栈工程师来写的,不懂前端技术是不可能写好模板文件的。
但不管怎么样,从编译和运行的角度来看,后端模板技术不适合前后端分离的架构,因为ftl之类的文件并没有很好的IDE支持,另外把数据随页面一次编译装配再加载到页面性能不高,采用ajax用户可以快速先看到页面,这比等着一个空白窗口会给人更多愉悦感。


前后端分离架构的接口设计

在前后端分离架构中,前端和后端都专注于自己的技术领域,但要完成功能他们又要很好的配合,这时团队的作用就很明显。前后端分离架构更适合大项目,对于人手极为有限的小项目来说,一个人全都搞定最省事,但对于多人的团队来说,前后端分离要求有更多的沟通,沟通成本会明显上升,要知道沟通一多,矛盾必然也多,所以大家一起玩就一定要定好规则,没有规则就会乱糟糟。
从架构上来说,前端要沟通的最多的无非是需求和接口,前端需要比照着原型图、设计图来做,因此常与产品经理和设计师沟通,另外前端需要很多数据接口,这需要后端的支持,想像一下,如果团队里有五个前端五个后端,如果没有很好的接口规范与沟通模式,那么这五个前端常常需要去找后端看接口,比如加一个参数,或某个值传的不对,或者前后端定的不统一,或者数据格式没商量好等,那么后端工程师哪还有时间写代码?而前端工程师也要花费很多口舌。
今天我们不谈前端与UI或需求的沟通,因为大多情况下原型图的格式各个公司都差不多,而每个公司甚至团队的接口文档(后端提供的接口说明)可能千差万别,有很多还没有文档,两个人商量好了,代码也写了,如果某一天又来了个新人,那全蒙了,他需要看懂前端代码和后端代码甚至数据库,再结合需求文档,再与若干人做一系列沟通才有可能弄懂到底是怎么实现的,如果团队的人更多,则情况会更复杂,尤其一项目里只有一个后端,有好几个前端的情况下,没有好的文档,一堆人去找这个后端问,情况可想而知。
实际工作中大家用的最多的文档是word、Excel、txt,我觉得这几种格式都很不好,word多人编辑不方便,而且修改起来麻烦,excel和txt我觉得纯属应付,根本不适合做接口文档。
也有很多公司在这方面做的很好,如开发了一个解决这个问题的系统,或者有钱干脆去买一个,在有新接口或改动时,直接在系统里改,大家都看得到。
对于没有这样条件的团队,我的建议是,不如约定好一种格式,做好规范,减少沟通成本。
我推荐使用json文件格式,JSON是一种前后端都支持的很好的数据交换格式,它小巧、轻量、易于处理、易于理解,修改丰收来很容易,而且,等有了时间和精力,可以写个小程序把JSON转换成任何你需要的文档格式,比如把json格式的接口文档转成html发布到某个网站下,如果你愿意,可以让程序自动地做这件事,只要接口有变更,马上转换并发布到网站里。
比如,我们可以这么定义一个接口:

{
    project:'erp',
    basePath:'http://m.co.erp/rest/',
    [{
        name:'获取用户列表',
        url:'usr/list',
        author:'唐建国',
        https:false,
        method:['GET','POST'],
        params:[{
            pageNo:'页码',
            defaltVal:1,
            required:false,
            type:'int'
        },{
            pageSize:'每页大小',
            defaltVal:20,
            required:false,
            type:'int'
        }],
        headers:{'content-type':'application/html'},
        response:{
            retCode:{
                name:'返回码',
                type:'int',
                comment:'1成功,0失败'
            },
            rows:{
                type:'array',
                comment:'用户列表数据',
                fields:[{ 
                    account:'帐户名', 
                    type:'string'
                },{
                    userName:'用户姓名',
                    type:'string'
                },{
                    age:'年龄',
                    type:'string'
                },{
                    sex:'性别:1男,2女'
                    type:'boolean'
                }]
            }
        },
    }]
}

以上只是简单的写了一个格式,仅做参考,另外关于这个接口的描述,样例地址,都可以定义进去,这种方式很容易阅读,输入和输出很清楚,团队只要商量好,形成规范,以后有了新接口或改了旧接口,只用在这上面改动一下就可以了,而且用大多数的文本工具都可编辑,提交到SVN,GIT也容易,想一想,这会减少多少沟通成本呀。

如果你喜欢看html格式的,没问题呀,写个程序,无论是java还是js,都可以很容易把上面的内容转成html文档,再也不用打开庞大的word来编辑了。

也许你觉得上面说的方式很low,你的公司或项目中已经有了更加高大上的方式,也希望你能分享出来,如果你的团队在前后端分离架构中遇到了接口设计上的问题,希望上面的思路对你有所启发,解决问题并不一定要直接弄个高大上的,这种简单的定义,只要商量好,要省事的多,而且写这种文档很节省时间,只要写好一个JSON接口模板,以后直接拷贝下修改几个字段,文档就出来了。
程序员何苦为难自己。

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值