我们在开发中,经常需要给别人提供一个接口进行调用,那么,我们在提供这些接口的时候,有哪些注意事项呢?
首先,我们提供的接口大致分为两种,一种是公开出去的接口,别人都可以申请调用的那种,还有一种是内部接口,只有内部人员才能调用的。
其实,不管是啥接口,都需要注意以下内容:
随便说两句:这个问题是一个粉丝提给我的,他说在别人的面试题文档中看到过类似的问题,但是那个答案一看就是 GPT 生成的,罗列了一堆正确的废话,想让我展开说说,以下是我的一些思考。大家可以看下和 GPT 内容的区别。
1、安全性:这个不管是内部还是外部接口其实都需要关注的,只不过有的时候内部接口可以不必要做的那么重。主要就是就是授权机制、数据传输的安全性这两个方面了。
授权机制的话可以是 API 密钥,也可以是认证相关的,比如 OAuth、JWT 等等。如果是需要和用户信息相关的,可能需要登录的话就需要 OAuth、JWT 这些,如果不需要用户鉴权的,可以直接用API 密钥来控制。
大家如果对结果一些开放平台就会知道,他们都要求你先在上面注册一个应用,然后给你发放密钥,你就可以通过这个密钥进行访问了。这个密钥,就是唯一能证明你身份的。作为 API 的提供者,我们就可以识别出来是谁在调用我们,如果遇到一些安全问题,我们就可以针对指定的密钥做限流、或者封禁。
然后在数据传输上,一般还会约定加解密、加解签,来保证数据的安全性和不可篡改性。这相当于是双方的一个握手,确保数据是从我这里发出的,中间没有经过别人的修改,并且即使别人拦截到数据了,他也无法拿到具体的明文内容。详见:
2、访问控制:这个其实和上面的安全性有点像,也是安全性的一种,单独要提一下就是比较重要的,比如上面我们提到过的密钥,它不仅可以做调用者的记录,我们还可以做访问控制,不仅是前面提到的限流、还可以做一些权限管控,可以基于密钥来控制可以访问哪些接口,以及不能访问哪些接口。
3、通用性:当我们在给别人提供接口的时候,最好是能考虑通用性,最好是这个接口不是定制化的,而是一个有类似需要的人都可以调用的,这就要求入参中可能要传入一些标识身份的字段,比如密钥、比如租户 ID、比如产品码等等,可以方便我们后续做扩展。
如果一个接口足够通用,那么后续在做对接的时候,就可以减少很多的开发工作量,而且你的系统的复杂度也会大大降低。
4、方便升级:当我们提供一个接口给别人的时候,你要确信,这个接口不可能一成不变,所以,可能需要提前考虑好后期的升级问题。这里面涉及到很多问题,比如说要不要做接口的版本控制,如果做了版本控制,则可以做更加精细的版本的管理,如果不做版本控制,那么则需要考虑升级的兼容性问题。
5、接口语义要明确:这个点其实很多人会忽略,举个例子,比如你定义了一个金额,类型你用的 string,那么别人传参数给你的时候,单位是元还是分?你需要明确清楚,还有最典型的返回值的 success,到底是表示调用成功了,还是表示处理成功了?这里面的差别很大(处理成功则不需要再检查 respCode 等字段,但是调用成功可能需要检查。。。)。
有人说,这不是最基本的么,确实是,但是我见过太多人定义的接口不够明确了,很容易产生误解。非常非常多,所以,对外接口的注释、文档需要尽可能的详细。因为一旦最后出现故障要扯皮的时候,人家不会说自己测试不充分,而是会甩锅给你说你接口定义不够清晰。
6、错误信息屏蔽:如果我们提供一个接口出去给被人调用,不管是内部还是外部,都不建议把异常抛出去,一方面别人也看不懂这个异常,而且这个异常别人也没办法处理,一旦在页面上展示出来一个 NullPointerException 就很尴尬。。。
所以,在做系统间交互的时候,我们需要用错误码体系来代替异常,可以定义一套错误码给别人,所有的异常自己都吃掉,而不是抛给别人。
7、自我保护机制:当一个接口提供出去之后。就一切都变得不可控了,你根本不知道他会怎么调用你,所以你需要做好悲观思想,那就是做好足够的自我保护,一些基本的日志肯定是要打印的,然后一些边界值的校验也是必须的,还有就是一些限流、降级、熔断的机制你也需要考虑起来。
✅为什么一定要做限流?不应该服务好客户吗?不应该是加机器吗?
8、RPC 接口特别注意:因为 RPC 的调用方式,别人往往需要依赖我们提供的API 做调用,所以,API 中有几个点需要注意的:
1、方法的入参和出参需要可序列化,即实现Serializable 接口,否则在序列化和反序列化过程中会报错。
2、方法的出参最好带上 success、respCode、respMsg 等固定字段,用来表示是否成功以及响应码和响应信息。
3、接口中尽量用包装类,而不是基本数据类型, 避免默认值导致误解。
4、接口出入参中,不要使用枚举,而是直接使用字符串,避免升级过程中导致序列化异常。而且一旦用了枚举,新增一个枚举项的时候,可能会要求所有调用方都做升级,否则就可能会出现枚举转换异常,这个也不太好。
5、是否成功这个字段,要用 sucess 表示,而不是 isSuccess 表示。