当前公司自主开发的一个AI图片识别项目,需要对外开放提供接口,领导二话没说把这个任务交给我来做,算是对我的一次考验。虽然以前自己没有设计过接口,但是调用过别人写的接口,如百度提供的接口,还有以前在项目中调用别人的接口等等。感觉调用别人的接口还挺方便的,自己来设计的时候,真不知道如何下手。然后去查看学习各种教程,开始进行接口的设计与开发工作。

 

设计原则

鉴于目前的网络环境形式,设计的首要原则是安全*原则,如果设计的接口不能保证其安全性,其他的活都相当于白干了。其次是简单原则,我认为调用接口的方式越简单越好,因为现在的人都很懒,这一点百度做得很好,调用他们的接口非常简单。如调用百度地图API,一个key就够了。目前只考虑到这两点,其他的还没有总结出来。

 

开发环境

Node.js + WebStorm + MySQL//说明:公司选择JavaScript作为后台开发的主要语言,开发难度估计只有Java的一半,可是现在使用的公司却非常少,搞不懂为什么。据统计NPM上面包的下载量和MAVEN的包下载量不是一个量级的,使用NPM的人超多,比用MAVEN的人多多了。

 

整体设计

这个接口的*终成型不是一下子全部就实现了,而是在工作中不断地改进,在每次改动中不断地变得越来越好,才算完成一个初步的版本。写代码就好比谈恋爱,两个人不可能一下子熟悉起来,立刻热恋,然后马上结婚,特例除外。在开发的过程中需要一直不停的更改,即使是上线了也有可能还需要修改,没有*终版本,因为需求的变动是不确定的。

这个接口是于一个独立的项目,为了在部署时方便,也为了调用时不和正式项目发生冲突,所以单独进行开发。所有的请求分为两大类,一类是获取用户token的请求,一类是进行业务操作的请求。

请求处理的先后顺序:请求拦截器—>获取用户token—->其他业务操作。如下图:
%title插图%num

 

开发过接口的人都知道,一般来说接口是没有页面的,只有后台;并且出于安全起见,所有的请求全部为POST请求。按照上面的设计来进行开发,获取用户token的请求不会被拦截器拦截,这步操作有些类似于用户登录的操作。其他的业务操作全部需要先经过拦截器先处理,验证通过后才放行,验证不通过则返回错误信息。

获取用户token时,需要传递三个参数,用户名、用户密码和一个秘钥key(UUID生成),其中用户密码和秘钥key都使用MD5加密。MD5加密不可逆,为了防止敏感信息被别人窃取,所以采取加密传输。验证通过则返回用户token和私钥,有效时间都是一个小时。秘钥key没有采用特殊的生成规则,比如用户ID+日期+项目名称+随机数字。使用简单的UUID生成32位长度的随机字符,我觉得很low,可是破解的概率*小,既简单又安全还实用。

返回的状态码和消息只有三种:接口调用失败,业务操作成功,业务操作失败。*开始设计时还加了一种接口调用成功,可后来转念一想,这一步有些多余。如果接口调用成功,那一定会进行业务操作,剩下的则是业务操作的事情了,所以把接口调用成功这一状态取消了。

所有操作分为三种情况:

接口调用失败—->返回错误信息;

业务操作成功—>返回操作成功信息;

业务操作失败—->返回业务操作失败信息。
%title插图%num

拦截器设计实现。拦截器用来拦截业务操作的所有请求,进行安全验证。验证的主要内容有:请求IP地址验证—->用户token验证—>rsa签名验证—>秘钥key验证。只有全部通过验证后才放行,否则返回错误信息。如果不清楚rsa加密方式的朋友可以先去百度百科里面了解一下rsa加密方式。

至于业务操作的设计则没有什么特别之处,和平常的增、删、改、查差不多。写一点,关于参数处理,如果可以的话,*好要在后台进行参数校验,我坚信一点,永远不要相信用户会按照你设计的方式来进行操作。所以对于用户输入的所有参数自己会严格验证,验证通过后才让程度进行下一步操作。

 

接口测试

由于接口没有页面,测试时不像一般的页面那样方便,只能采取其他方式来进行测试。同事建议我使用谷歌的一个专业测试软件Postman,自己使用后觉得还将就,不过我认为还是不太方便。然后换用了另外一种本人认为更简单的方式,使用WebStorm 创建一个新项目,只需要导入可以发送POST请求的包即可,然后一个test.js文件搞定所有测试。

秘钥key使用rsa(私钥)加密,token原样传输,参数使用aes加密,然后在在使用rsa(私钥)进行签名操作生成签名字符串。签名主要是为了防止数据在传输过程中被串改,敏感数据则使用rsa私钥加密,然后用公钥解密,也可以使用公钥加密,私钥解密,主要是为了防止被窃取。但是我了解到的是rsa签名只能使用私钥,再使用公钥验证签名。

%title插图%num

   自己创建一个新项目来进行测试,一个接口接着一个接口的测试,很快全部测试完毕,Word文档也同步写好。测试工作完成则表明接口开发的初步版本完成。
遇到的问题
       开发和测试中肯定会遇到各种各样的问题,在此只写几个有代表性的问题。
       *个问题,rsa加密有长度限制,网上说只能加密117个字节,当我加密的数据太长时果然出现问题,比如加密Base64格式的图片信息出问题。为了解决这个问题,所以使用aes来进行加密和解密数据,图片信息也不受影响。
        第二个问题,使用rsa加密的数据中可能会含有加号,开始时我是放在URL中进行传输,之后在解析时会将加号解析为空格,这个问题是采了很久的坑才知道的。左思右想才想到一个很好的解决办法是在解析URL参数后,使用正则表达式将字符串中的空格全部替换为加号,测试完全可行。
       这种方式对于有单个加号的数据可行,可是后面测试时,问题来了。一次数据验证签名一直没有通过,我很奇怪,刚才还好好的,怎么一下子就不行了呢。仔细查找原因才知道,在使用rsa进行数据签名操作时,字符串中出现了三个连续加号如下:
FayA44XDO5jeqDbafkMqzogMZHvJ+l3CX3myjiPYrsyyXV7KJvgjgNeVf+++m/UDNrcTuFQ2DnzR+rngygfJ0Q==  这是我意识到问题的严重性,rsa操作生成的数据*好不要拼接在url中传输,否则会出问题。如果一定要拼接在URL中进行传输,则对加号一定要特殊处理。我的处理方式是所有参数全部放在body中进行传输,这样解析时就不会出问题。
        第三个问题,数据在传输前是JavaScript中的一个对象,不便于传输,为了解决这个问题尝试过不少方法,*终决定采用JSON.stringify()//JSON.parse()这一对函数来解决。因为数据加密只能加密字符串,可以使用JSON.stringify()函数将JSON对象转换为字符串,然后进行加密传输。对字符串进行解密后在使用JSON.parse()函数将字符串转换为JSON对象。测试可行,圆满解决这个问题。
        第四个问题,获取token的请求和其他大的业务请求操作不太一样,在拦截器中我做了一次请求地址的判断,如果请求地址是获取token则直接跳转到对应的方法,否则放行进行其他业务操作。这样做虽然每一次都需要做一次请求判断,可是代码量大大滴减少了,因为每一个请求都需要做IP地址验证,如果不这样处理,则需要把请求地址验证的方法单独写到一个文件中,放在*前面,我没有这样做,感觉这样做比较麻烦,还是使用一个拦截器方便、简单些。
总结
      从这次设计、开发、测试接口中学到不少的东西,虽然这个接口项目还在不断地完善,不过我知道我肯定会做得越来越好。比如关于安全方面,后期肯定还会添加验证,用于防止攻击,如防止频繁的请求攻击,只限制post请求进入等等。
      真实的项目开发中学习到的这些东西印象都会非常深刻,不容易忘记。自己平时也在学习其他的编程语言比如Python,学习完后没有使用起来会很快忘记。在工作中则不一样,可以做到真正的学以致用,学习到的东西需要马上使用,这时印象会非常的深刻。
      学到老,活到老是我一贯坚持的信条,写这篇博文分享出来也算是对自己工作的一种总结,一种学习。如果各位开发的朋友有不懂的或者是有更好建议,欢迎留言。