高诚智能家居协议思考
借此机会重新理顺一下智能家居部分的网络通讯协议使用情况,并总结一下做为指导。当然只是抛砖引玉,需要大家一起商议后决定。
规范
首先定义一些规范,提出一些硬性要求。
URI规范
URI 表示资源,资源一般对应服务器端领域模型中的实体类。
- 不用大写
- 用中杠-不用下杠_
- 参数列表要encode
- URI中的名词表示资源集合,使用复数形式
JSON规范
- 不要使用缩写
- 统一用驼峰命名法
- 不要使用_或者-
- 用名词复数表示集合类型
Http部分
规定
- App的初始化数据尽量都用http协议获取
- 页面的初始化数据尽量都用http协议获取
待定
MQTT部分
使用场景
- 所有对智能家居的设备、传感器等硬件操作都尽量使用MQTT协议
- 所有需要双向通讯(确切的说是需要后台主动推送给前端的情景)的部分都尽量使用MQTT协议
使用列举
主机操作
- 主机布防状态变更
传感器操作
- 传感器状态变更
设备操作
- 设备状态变更
界面相关
- 消息提示:比如底部导航栏的tab勋章提示
错误处理
- 不要发生了错误但给2xx响应,客户端可能会缓存成功的http请求;
- 正确设置http状态码,不要自定义;
- Response body 提供 1) 错误的代码(日志/问题追查);2) 错误的描述文本(展示给用户)。
对第三点的实现稍微多说一点:
Java 服务器端一般用异常表示 RESTful API 的错误。API 可能抛出两类异常:业务异常和非业务异常。业务异常由自己的业务代码抛出,表示一个用例的前置条件不满足、业务规则冲突等,比如参数校验不通过、权限校验失败。非业务类异常表示不在预期内的问题,通常由类库、框架抛出,或由于自己的代码逻辑错误导致,比如数据库连接失败、空指针异常、除0错误等等。
业务类异常必须提供2种信息:
- 如果抛出该类异常,HTTP 响应状态码应该设成什么;
- 异常的文本描述;
在Controller层使用统一的异常拦截器:
- 设置 HTTP 响应状态码:对业务类异常,用它指定的 HTTP code;对非业务类异常,统一500;
- Response Body 的错误码:异常类名
- Response Body 的错误描述:对业务类异常,用它指定的错误文本;对非业务类异常,线上可以统一文案如“服务器端错误,请稍后再试”,开发或测试环境中用异常的 stacktrace,服务器端提供该行为的开关。
常用的http状态码及使用场景:
状态码 | 使用场景 |
---|---|
400 | bad request 常用在参数校验 |
401 | unauthorized 未经验证的用户,常见于未登录。如果经过验证后依然没权限,应该 403(即 authentication 和 authorization 的区别)。 |
403 | forbidden 无权限 |
404 | not found 资源不存在 |
500 | internal server error 非业务类异常 |
503 | service unavaliable 由容器抛出,自己的代码不要抛这个异常 |
错误描述
{
"error": {
"message": "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $",
"code": 500,
"exception": {
"class": "com.google.gson.JsonSyntaxException",
"message": "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $",
"localized-message": "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $",
"cause": "java.lang.IllegalStateException"
}
}
}
错误请求头
{
"date": "Mon, 08 Jan 2018 03:07:08 GMT",
"server": "nginx/1.10.3 (Ubuntu)",
"connection": "keep-alive",
"content-length": "237",
"content-type": "application/json"
}
接口版本(Versioning)
个人倾向于将版本号放在HTTP/MQTT头信息中,虽然不如放入URL中更直观,但是不方便我们统一管理,因为在前端URL是拼出来的String,请求头是统一个对象去设置,除非有特殊情况,某一个接口需1.0版本,某一个接口需2.0版本,这就另当别论,到时候统一商量,在拼这个URL的时候,放到固定目录(位置),如:smarthome.aghl.com:8080<u>/版本(一般用v1、v2)/</u>user 统一放在一级目录,这样的前端在拼接的时候,统一放到某个位置,也就方便管理了。
URL失效
随着系统发展,总有一些API失效或者迁移,对失效的API,返回404 not found 或 410 gone;对迁移的API,返回 301 重定向。
安全
待定