本人技术不高,设计有缺陷的地方还请各位指点一下,或者有地方不明白可以 评论一下,我也会说出自己的思路。第一次写文章,不知道说啥好,就直接开搞把
开发项目:房产类APP、H5
开发语言:PHP
语言框架:Yii
框架选择:之前已经用Thinkphp框架做了套小程序接口和后台管理,想换个框架来重写接口,在 Yii 和 Laravel中选择,经过多方面的考虑和个人喜好最后选择的Yii。
既然是混合开发 那么就需要无状态登录,简单介绍一下:
传统的web端登录,是将登录信息缓存到服务端的session中,每个session有唯一的sessionId,浏览器请求服务端会自动在请求头的cookie中带上sessionId,服务端得到sessionId在session缓存器中获取数据。
无状态登录有哪些优势
1.服务端不需要缓存用户信息,可以减少服务器压力
2.token缓存在客户端,服务器重启,登录状态不会失效
3.容易扩展,如果使用负载均衡 传统登录虽然可以实现,但是成本和时间会大大提高,使用TOKEN就不需要麻烦,只需要多台服务器使用相同解密代码即可
接口安全
JWT(JSON Web Token)签名算法 SHA512,考虑到有些隐私的数据,增加了新的字段,并且使用 RSA(非对称算法) 进行了加密。
为什么要增加字段而不是 直接使用RSA算法对Token进行加密:RSA加密解密速度比对称算法要慢的多,会严重影响接口响应速度,浪费服务器资源。增加字段,不需要每次都解密,只有需要使用的时候解密就可以了。
我自己封装好了JWT和RSA加解密,代码有点多 就不好贴出来了。
接口数据安全
数据安全依然采用SHA算法签名验证,每一次请求 把请求的内容和KEY 一起加密,并且设置接口有效期 5秒左右,服务端接收到数据 进行 签名和有效期验证,由于 KEY是私密的别人无法得到就算拿到这个包也无法从服务端拿到数据。
Restful 风格设计
标准的Restful风格,我是不太喜欢,根据这个风格调整了下,GET 查询,增删改用POST,就只用了这两种方式。
版本号方式:
apiv1.xxxx.com
接口返回结果
响应码:
class Code {
const success = array(
2000 => ['status' => 2000, 'msg' => '查询成功', 'sysMsg' => 'success', 'is' => true],
2005 => ['status' => 2005, 'msg' => '查询成功,无数据', 'sysMsg' => 'success', 'is' => true],
2001 => ['status' => 2001, 'msg' => '操作成功', 'sysMsg' => 'success', 'is' => true], // 更新或插入操作
2002 => ['status' => 2002, 'msg' => '后台已执行', 'sysMsg' => 'success', 'is' => true],
2004 => ['status' => 2004, 'msg' => '删除成功', 'sysMsg' => 'success', 'is' => true]
);
const error = array(
4000 => ['status' => 4000, 'msg' => '未执行任何操作', 'sysMsg' => 'error', 'is' => false],
4001 => ['status' => 4001, 'msg' => '验证码错误', 'sysMsg' => 'error', 'is' => false], // 验证码用户名或密码错误过期
4003 => ['status' => 4003, 'msg' => '无权访问', 'sysMsg' => 'error', 'is' => false],
4004 => ['status' => 4004, 'msg' => '记录不存在', 'sysMsg' => 'error', 'is' => false],
4006 => ['status' => 4006, 'msg' => '格式不正确', 'sysMsg' => 'error', 'is' => false],
4022 => ['status' => 4022, 'msg' => '缺少参数', 'sysMsg' => 'error', 'is' => false], // 自定义错误信息
4029 => ['status' => 4006, 'msg' => '请求次数超过限额', 'sysMsg' => 'error', 'is' => false],
);
public static function getSCode($code)
{
return self::success[$code];
}
public static function getECode($code)
{
return self::error[$code];
}
}
复用类
Trait ResponseCode{
private static $instance;
public static function successResponse($code, $data)
{
$code = Code::getSCode($code);
$code['data'] = $data;
return json_encode($code);
}
public static function errorResponse($code, $msg = '')
{
$code = Code::getECode($code);
if ($msg != ''){
$code['msg'] = $msg;
}
return json_encode($code);
}
}
如何使用?
引入 ResponseCode 类 填入响应状态码即可
return ResponseCode::successResponse(2000, $data);
Yii框架数据库操作
在这也是 纠结了一下,活动记录也就是模型果断放弃的,又在 查询器和 createCommand做选择 查询器 可读性更好些,createCommand 后期做分布式数据库很方便。
最后还是选择了 createCommand ,它更高效,不会产生多余的SQL,我也进行了简单的封装,看起来不是那么啰嗦, 满屏幕的 'select'的字符串,写起来都很头疼。
代码如下:
class Sql
{
private $db;
private static $sql;
function __construct($name = '')
{
if (!$this->db) {
$this->db = \Yii::$app->db;
}
if ($name !== '') {
$this->sql = " from {{%$name}}";
}
}
public function select(string $fields)
{
self::$sql = " select " . $fields . self::$sql;
return $this;
}
public static function from(string $name)
{
self::$sql = " from {{%$name}}";
return new self();
}
public function map($map = '')
{
if ($map) {
self::$sql .=' ' . $map;
}
return $this->db->createCommand(self::$sql);
}
}
如何使用?
use common\models\Sql;
$data = Sql::from('advert')
->select("id, title, CONCAT($dir, cateimg) as cateimg, page_url")
->map('where type = 1 and cityid = :cityid')
->bindValue(':cityid', $cityid)
->queryAll();
这样看起来 是不是 就舒服很多了,当然每个人想法不一样。
我个人喜欢原生的PHP,如果不是穷....
所以我的 工具类都是基于 原生PHP编写,自己写的看起来更清晰,也能够兼容于大部分的框架。
以上就是我的设计思路,欢迎各位朋友提出宝贵的建议!大家一起进步!