天天看点

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

作者:程序员高级码农II

规整化

本节讲解具体规整地方法,主要从接口设计、编码规范、集中配置、Cookie和Session、应用拆分和应用协调、日志6个方面进行深入讲解。在项目前期,后端架构需要充分考虑这几个方面。

注意:规整化是要把握一个度的,标准太高会拖慢项目进度,标准太低又达不到规整的目的,所以后端架构需要根据实际的团队水平和项目周期制定规整化的标准。

接口设计

后端应用程序可以看作一堆接口的集合体,因此,“规整化后端应用程序”应该先关注“接口设计”。由4.1.4小节后端应用程序的工作原理中介绍的“后端应用程序处理接口请求”可知,一个完整的接口请求包含7个部分,本小节将会对这7个部分进行详细的分析。

·请求的URL;

·请求的方式;

·请求的报文头信息,一般称为请求的Header信息;

·请求的报文体,一般称为请求参数;

·响应的状态码和状态码描述;

·响应的报文头信息,一般称为响应的Header信息;

·响应的报文体,一般称为响应数据。

注意:后端应用程序的接口一般被称为RESTful API,业内有很多关于RESTful API的设计规范。但是,不建议全盘照搬这些设计规范,因为现成的设计规范都过于完整,以至于开发者很难有耐心对其严格遵守。再者,设计规范的目的是统一规则、简化逻辑、便于团队合作,所以具体项目应该根据实际情况,制定尽量精简且有效的接口设计规范。

1.请求的URL

一个URL一般分为4部分,即协议、IP地址(域名)和端口、路径、参数,如图4.40所示。

(1)协议。一般为HTTP或HTTPS。协议这部分在接口设计时可以先忽略,因为协议一般是整个网站系统统一的,单个接口无权决定使用的协议。而且一般情况下,无论使用HTTP还是HTTPS,后端应用程序的代码都不会有所差别。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

图4.40 URL的结构

(2)IP地址和端口。这里的IP地址一般为域名。IP地址和端口这部分在接口设计时也可以先忽略,其也是由网站整体规划决定的。

说明:一般情况下,接口的URL会与网页资源的URL有所区别,这个区别可以体现在域名上,如api.xxx.com,或者体现在路径上,如xxx.com/api/xxxx。

(3)路径。路径是接口设计中比较重要的部分。路径的作用是让Web应用服务器软件调用对应的后端应用程序的函数,所以从技术层面上讲,无论路径有多少层或者用什么单词,只要这个路径能与代码对应上,就是没问题的。但是,由于URL本身标记的是资源,所以URL上的单词最好都为名词,而且最好是名词的复数形式,如/zoo/animals。

而路径推荐分为三层,分别是模块、子模块和具体资源。模块指的是处理不同业务的后端应用程序;子模块指的是模块内部的分类;具体资源指的是对应具体资源的标识。具体资源内部还可以根据具体情况增加分层,不过最好不要超过2层。路径的分层对应关系如图4.41所示,其中,在实际编码中,路径分层会根据不同的框架有不同的映射关系,在Spring Boot框架中,模块一般指的是.war文件,子模块一般指XXcontroller.java文件,具体资源标识的是函数(需要加上请求方式才能唯一标识具体函数)。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

图4.41 URL中路径分层的对应关系

注意:模块的划分可以按照业务架构的子系统划分,业务架构设计可以参考2.1.1小节业务架构面临的挑战和2.2节业务架构的基本思路。后端应用程序的模块划分除了根据业务架构划分外,还需要考虑权限分类(普通用户和管理员)及并发压力(高并发接口和普通接口)等因素。

一些接口设计规范里强调版本管理,版本管理有利于对不同版本的后端应用程序进行管理,在不影响使用者使用旧版本接口的同时,提供新版本的接口。版本号可以体现在URL上,如/v1/zoo/animals,其中v1即为版本号,也可以体现在Header信息(报文头信息)中,不过体现在URL上比较直观和普遍一些。但是,版本管理的实质是同时运行旧版本和新版本的后端应用程序,那么有了新版本还有必要保留旧版本吗?答案是不是任何时候都需要保留旧版本,也就是说,不是任何后端应用程序都需要做版本管理。在实际项目当中,只需要对一些开放性的接口(被自身网站系统以外的软件使用)进行版本管理就可以了,不需要对网站系统内部的接口进行版本管理。

这是因为自身网站系统以外的使用者会有很多个,且大多都不愿意随着接口更新而立刻改变自己的代码,如果功能稳定的话,他们会更愿意继续使用旧版本;对于自身网站系统内部而言,接口使用者只是网站系统本身,代码修改起来比较方便,而且维护几个版本是需要一定成本的。因此,版本管理需要根据具体情况而定,并非所有接口都需要做版本管理。

注意:一般而言,“需要做版本管理的接口”和“不需要做版本管理的接口”需要区分出来,划分成不同模块(不同的.war文件),这样有利于管理。

(4)参数。问号以后都为参数部分,这部分不建议使用,参数部分应该放在请求参数当中,这样可以让URL精简一些。但是,当请求方式为GET时,则不得不把参数部分放在URL中,因为此时一些请求端是不允许有报文体的(如浏览器)。

当请求方式为DELETE时,一些规范推荐在URL中使用{}作为参数的标识,如http://hostname/user/user/{userid},其中,userid为需要删除的具体id。这是因为某些Web应用服务器软件可能会丢弃伴随DELETE发送的报文体。

不过,这种会丢弃报文体的服务器是不常见的,在默认配置下,Tomcat不会丢弃伴随DELETE发送的报文体。因此,当请求方式是DELETE时,还是推荐把参数放到报文体中,这样能统一接口设计逻辑。

综上,除非请求方式为GET,否则参数部分都应该放在请求参数当中。

2.请求的方式

请求方式表示对资源的操作类型,一般来说,通过“URL”和“请求方式”这两项才能唯一定位后端应用程序对应的函数。具体的请求方式及其对应的含义如表4.2所示。

注意:目前比较常用的HTTP版本是HTTP 1.1,而在旧版本HTTP 1.0当中,不支持PATCH请求方式。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.2 请求方式及其对应含义

在实际应用当中,一般使用的是GET、POST、PUT、DELETE,对应四个基本操作:查询、增加、修改、删除。请求URL和请求方式结合起来,即可表示为对某个资源的具体操作,即使不看接口文档,也能大概猜出接口的功能。当然,以上的请求方式其实只有字面上的含义,用DELETE标识更新操作也不会有问题,不过,这些都是约定俗成的东西,最好不要特立独行。

说明:对于修改操作,无论更新的是全部属性还是部分属性,其实都可以选用PUT或者PATCH,PUT更常用一些。

3.请求的Header信息

请求的Header信息(报文头信息)用于记录相关的请求属性,Web应用服务器会处理这种Header信息。Header信息的种类很多,但接口设计时一般考虑表4.3中的属性即可。其中,Accept属性的值保持默认(*/*,全部类型)即可,一般不需要设置;Cookie属性的值一般是服务器端通过Set-Cookie设置的,浏览器请求时会自动携带上,更详细的内容会在4.3.4小节中介绍;Content-Type属性对应请求参数的数据类型,这个一般需要手动指定,不然Web应用服务器无法把请求参数转换成对应的数据对象。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.3 接口设计时需要考虑的Header属性

Header信息可以被后端应用程序获取和使用,后端应用程序可以对一些自定义的Header信息进行处理,从技术层面讲,可以通过自定义Header属性给后端应用程序传递参数。但是,一般情况下,Header信息(除了Cookie外)都是Web应用服务器软件处理的,而Cookie在浏览器设置成“阻止Cookie”时,也不会自动保存和发送,因此,接口设计时最好不要添加自定义属性。

综上,接口设计只需要指定Content-Type属性即可,一般设置为application/json(对应JSON数据类型),但这需要与请求参数的数据类型匹配。其他Header属性保持默认即可,Cookie属性会在4.3.4小节中讲述用法,但不建议个别接口使用。

说明:请求时的Header信息记录了相关请求属性,其属性处理应该交由Web应用服务器处理,后端应用程序处理请求参数即可。对于“Web应用服务器软件处理Header信息”和“后端应用程序处理请求参数”这个划分需要明确,否则接口使用者会觉得很麻烦。

4.请求参数

请求参数(报文体)部分是根据每个接口的功能而定的,不过也应该遵守一定的规范,包括参数类型、参数结构、明确必填参数和可选参数等。

参数类型可以是JSON、XML、字符串等。在项目没有特殊要求的情况下,推荐使用JSON类型。这是因为目前JSON类型比较流行,而且相对于其他类型(如XML)更加易读和简洁,便于人工检查。JSON数据结构如代码4.17所示,XML数据结构如代码4.18所示。

注意:无论选择哪种参数类型,请求参数部分的参数类型必须统一,不能一个接口选用一个类型。

代码4.17 JSON数据结构

{

"id":"AA0302",

"name":"张三",

"class":"1-1",

"born":"2011.11.20"

}

代码4.18 XML数据结构

<?xml version="1.0" encoding="utf-8" ?>

<student>

<id>AA0302</id>

<name>张三</name>

<class>1-1</class>

<born>2011.11.20</born>

</student>

参数结构应该尽量简洁,层级最好只有一层,一些特殊情况除外(如批量添加等情况)。结构层级超过一层会让整体结构看起来有点混乱,以JSON数据为例,一层结构的数据和多层结构的数据对比如代码4.19所示。

代码4.19 一层结构的数据和多层结构的数据的对比

#一层结构的数据

{

"id":"AA0302",

"name":"张三",

"class":"1-1",

"born":"2011.11.20"

}

#多层结构的数据

{

"id":"AA0302",

"info":{

"basic":{

"name":"张三",

"class":"1-1"},

"born":"200.11.20"

}

}

明确必填参数和可选参数,必填参数需要明确,可选参数需要明确其默认值。以添加学生信息接口为例,其参数说明如表4.4所示,其中学生id由服务器生成。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.4 添加学生信息接口的参数说明

5.响应的状态码和状态码描述

当接口请求处理完毕后,会返回响应报文,其中,状态码标识的是此次请求的结果状态,状态码描述是状态码对应的简短文字描述。状态码大致有5个种类,如表4.5所示,其中,XX表示省略,如2XX的状态码包含200、201、202等状态码。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.5 状态码种类

状态码和状态码描述一般交由Web应用服务器填写,后端应用程序不需要关心。虽然后端应用程序可以修改状态码,但是一般不推荐这样做。因为状态码标识的是此次请求本身的状态,与后端应用程序的功能无关。例如,当请求参数填写错误时,后端应用程序会返回一个“参数错误”的结果,但是请求过程本身是没有问题的,所以返回的状态码应该是200(成功),而“参数错误”的结果应该放到响应数据(报文体)当中。

综上,接口设计其实不需要关心状态码和状态码描述。

6.响应的Header信息

响应的Header信息(报文头信息)用于记录相关的响应属性,大部分属性都是Web应用服务器根据“请求时的Header信息”和“后端应用程序返回的结果”自动填写的。响应的Header信息种类很多,但接口设计时一般考虑表4.6中的属性即可。其中,Content-Type属性是自动填写的;Set-Cookie属性一般由后端应用程序操作,一般情况下,该属性对应的值会被客户端保存,当客户端再次发送请求时,会被记录在请求Header信息的Cookie属性当中。更详细的内容会在4.3.4小节中讲述。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.6 接口设计时需要考虑的响应Header参数

接口设计可以使用Set-Cookie属性,但是由于Cookie在浏览器设置“阻止Cookie”时是不会自动生效的,所以Set-Cookie一般也是不推荐使用的。

因此,一般情况下,接口设计不需要关心响应Header参数。

7.响应数据

响应数据(报文体)部分是根据每个接口的处理结果而定的,不过也应该遵守一定的规范。

数据类型最好与请求参数的数据类型保持一致;数据结构,响应数据中最好包含“结果代码”和“结果代码对应的描述”,把响应结果数据放到固定的字段里面。以获取学生信息的接口为例,响应数据如代码4.20所示,其中,数据类型为JSON。

说明:这里没有强调数据层级限制,这是因为响应数据一般比较复杂,采用合理的数据结构能方便使用者使用。

代码4.20 获取学生信息接口的响应数据

{

"errorCode":"200", //结果代码

"message":"成功", //结果代码对应的描述

"result":{ //结果数据的字段

"count":20, //学生总个数

"list":[ //筛选出的学生列表及其信息

{"id":"AA0302", "name":"张三", "class":"1-1", "born":"2011.11.20"},

{"id":"AA0303", "name":"李四", "class":"1-1", "born":"2011.10.20"},

{"id":"AA0304", "name":"王五", "class":"1-1", "born":"2011.11.22"},

{"id":"AA0305", "name":"赵六", "class":"1-1", "born":"unknown"}

]

}

}

相对应的,响应数据也应该有说明表格,以代码4.20所示的响应数据为例,其参数说明如表4.7所示。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

表4.7 获取学生列表接口的响应数据说明

8.总结

综上7点的分析和描述,接口设计的逻辑如图4.42所示。URL的路径部分负责划分资源模块,请求方式负责规划对资源的“增、删、改、查”操作,请求参数作为处理参数,响应数据作为处理结果。一般而言,接口设计需要关注的只有4部分,即URL中的路径部分、请求方式、请求参数和响应数据。

注意:当请求方式为GET时,请求参数需要放在URL上。

大型网站架构的技术细节:后端架构规整化-接口设计如何实现?

图4.42 接口设计逻辑

本文给大家讲解的内容是大型网站架构的技术细节:后端架构规整化接口设计

  1. 下篇文章给大家讲解的内容是大型网站架构的技术细节:后端架构规整化编码规范
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持

继续阅读