Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

API接口通讯参数规范(2)

lex-wu 2019-02-22 17:16:00 阅读数:204 评论数:0 点赞数:0 收藏数:0

针对【API接口通讯参数规范】这篇文章留下的几个问题进行探讨。

问题1

试想一下,如果一个http请求返回一个500给我们,那我们是不是都不用看详情都知道该次请求发生了什么?这正是一个标准的结果码意义所在。在公司所有的系统中,API遵循同一套结果码,那这样同事A在调用同事B的接口时,对于返回的结果码是非常具有可读性的,我们不用面对面交流都知道返回的结果是一个什么样的情况。

XML方案

在此先给出上一篇文章针对Result的另一个方案,是基于XML来定义结果码的,可能有些公司喜欢XML这种配置文件,因为可以不用重新发布应用程序(其实大多数情况下还是需要重新发布的,后面会讲解)。这里面的主要变化是我们不再从枚举ResultCode中获取提示信息,这些提示信息会放在XML上,看看我们的Result中的Message属性的变化

 /// <summary>
/// 结果消息
/// </summary>
public string Message
{
get { return _message ?? XmlResultCodeHelper.GetResultMsg((int)Code); }
set { _message = value; }
}

看看我们的这个帮助类

 /// <summary>
/// xml结果码帮助类
/// </summary>
public class XmlResultCodeHelper
{
private static List<XmlResultCode> xmlResultCode = new List<XmlResultCode>();
//获取xml里面对应的msg
public static string GetResultMsg(int key)
{
if (xmlResultCode.Count==0)
{
dynamic type = (new ErrorCodes()).GetType();
string currentDirectory = Path.GetDirectoryName(type.Assembly.Location);
string path = currentDirectory + "\\XmlResultCodes.xml";
xmlResultCode= path.XmlDeserializeFromFile<List<XmlResultCode>>();
}
var code = xmlResultCode.FirstOrDefault(q => q.Code == key);
if(null == code)
throw new InvalidOperationException("没有配置对应的xml节点");
return code.Msg;
}
}
/// <summary>
/// xml结果码
/// </summary>
public class XmlResultCode
{
public int Code { get; set; }
public string Msg { get; set; }
}

这个类主要是帮助我们获取到XmlResultCodes.xml并且返回里面对应的msg,这方法里面的xml反序列方法我就不再贴出来了,大家百度一下即可。

看一下我们的XmlResultCodes.xml,这里看得出是一个键值对

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfErrorCode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ErrorCode>
<Code>1</Code>
<Msg>操作成功</Msg>
</ErrorCode>
<ErrorCode>
<Code>10</Code>
<Msg>操作失败</Msg>
</ErrorCode>
<ErrorCode>
<Code>11</Code>
<Msg>登陆失败</Msg>
</ErrorCode>
<ErrorCode>
<Code>13</Code>
<Msg>参数不正确</Msg>
</ErrorCode>
<ErrorCode>
<Code>20</Code>
<Msg>用户不存在</Msg>
</ErrorCode>
<ErrorCode>
<Code>21</Code>
<Msg>没有数据</Msg>
</ErrorCode>
</ArrayOfErrorCode>

再看看我们这个ResultCode枚举,对比上篇文章,已经不需要DisplayAttribute了

 public enum ResultCode
{
/// <summary>
/// 操作成功
///</summary>
Ok = 1,
/// <summary>
/// 操作失败
///</summary>
Fail = 10,
/// <summary>
/// 登陆失败
///</summary>
LoginFail = 11,
/// <summary>
/// 参数不正确
///</summary>
InvalidParams = 13,
/// <summary>
/// 用户不存在
///</summary>
NoSuchUser = 20,
/// <summary>
/// 没有该数据
///</summary>
NoRecord = 21,
}

那这种情况ResultCode对我们的意义是什么呢?且看下面例子

//情况1 
return Result.FromCode(13);
//情况2
return Result.FromCode(ResultCode.InvalidParams);

我们虽然英文口语不一定流利:),但是凭借我们的睿智,肯定会让我们选择情况2使程序具有更高的可读性,不然新人接手项目,吐槽是少不了的,难保自己过了段时间再看这样的设计,这返回的13是什么鬼?

OK,XML的方案基本可以了,总结一下步骤:

1.  在ResultCode中定义好自己的英文(使程序具有更高的可读性)和对应枚举的数值

2.  在XmlResultCodes.xml中定义这个数值对应的提示信息

 

同样我们也会审视这个设计方案的问题所在:为什么会采用XML?就是冲着不用重新发布嘛。是的,改提示信息是可以不用重新发布,但是在xml里面添加了新的节点呢?添加了之后我们得用啊,一样要在业务中调用这个新的节点,还不是一样要重新发布?这样看来我们基于这个XML的设计方案并没有完全达到我们的初衷的。

  怎么办?且看下面的问题。

  问题2

我们如何做到统一呢?中心式的管理,在管理后台中,把所有的结果码和对应的消息都写入数据库,然后通过Redis加载作为缓存,在获取提示信息的时候访问Redis返回我们需要的信息。

 public class ResultCodeHelper
{
public static string GetResultMsg(int key)
{
//从redis数据库根据key获取到value
 }
}

这里只是伪代码,大家根据自己的Redis的熟知情况设计方案。

 

现在这个ResultCode的增删改都只能让管理员在管理后台操作了,开发人员最好是有权限能查看到ResultCode的所有结果码和信息,这样在新增之前才能知道是否存在类似的结果码进而避免重复。修改和删除结果码?最好不要,你有见过Http状态码的更改吗?这种公司级别的通讯规范,作为基础设施架构就最好先设计和定义,后续项目多起来,都可以有据可依。

来看一下我们结果码定义和使用的流程:

1. ResultCode在管理后台的定义和储存

2. 加载到Redis并获取对应值的信息

3. 每个项目都定义好自己的ResultCode对应的枚举和值(使程序具有更高的可读性)

 

至此我们通过DisplayAttribute和XML获取提示信息这两种方案都已经被分布式缓存Redis方案代替了,我们做了那么多,并且耦合了Redis缓存,这样做究竟有什么好处呢?就像我们的标题阐述的主题一样,规范!规范会让后续的项目管理花费更少的effor。

 

让我知道如果你有更好的想法!

 

版权声明
本文为[lex-wu]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/lex-wu/p/10398575.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领