laravel项目稳定系统如何保证兼容的同时进行持续迭代设计?

运行环境

laravel8+php7.4(提供纯api服务,对接web/安卓/ios)

情况说明

这是一个后台管理系统,有web端也有app端。在持续迭代设计上有两个痛点:

  • 所有小版本迭代需要保持老版本的兼容(前端不需要强更)
  • 有rbac存在,所以迭代需要继承老版本的权限,比如 order/list 接口后续不管怎么迭代已有该权限的管理员还是需要照样有该接口的权限

1.当前结构:

app
|----controller
|--------OrderControler.php
|--------UserController.php
|----service
|----model
...
  1. auth表:

    id route
    1 order/list
  2. rbac权限

    id 管理员id auth_id
    1 1 1

当前想法

  1. 目录结构:

    • 最新版本的controller继承上一版本的controller,然后有变更的接口就复写action,有新增的就直接加action
    • route区分 v1/order、v2/order版本接口来兼容老接口
      app
      |----controller
      |--------V1
      |------------OrderControler.php
      |------------UserController.php
      |--------V2
      |------------OrderControler.php
      |------------UserController.php
      |----service
      |----model
  2. 当前思路暴露的问题

    • 每迭代一次路由就更换了一次(由v1/order变更成了v2/order),导致前端必须同步强更。如果只是web端其实影响不大,但是这个项目还有App端,尤其是小版本如此频繁的强更不切实际…
    • auth表会增加历史路由,rbac权限表需要将已有v1权限的管理员将v2的权限也同步进去。甚至存在需要将已有v1权限的管理员将v3的权限同步进去(某些接口直接从v1迭代至v3的)
    • 给管理员分配权限时,权限树会增加v1/v2/v3…很多历史结构,如何合理的保持干净结构
      id route
      1 v1/order/list
      2 v2/order/list

另外一种

所有接口识别query携带version参数,根据version进行分发到底执行哪个action,但是这里在哪个位置实现分发有点别扭。我是想再route层就进行识别分发,类似于这种在最顶层入口判断分发:

Route::get('order/list',function(Request $request){
    if($request->get('version')=='v3'){
        调用 v3/OrderController
    }else{
        调用 v1/OrderController
    }
});

但是在路由层写闭包写逻辑肯定是不好的,所以这种方案想了解下有没有什么基于路由全局判断自动分发的写法(或者说是在哪个位置节点能统一判断分发)。。。

最后

请问各位都是如何合理的设计这种系统持续迭代的?请不吝赐教真诚学习…[膜拜]

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案
  • 这样可否
//  api.php
Route::get('/user/create', [\App\Http\Controllers\User\CreateController::class, '__invoke']);
// User/CreateController.php
<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class CreateController extends Controller
{
    public function __invoke(Request $request)
    {
        $version = $request->header('version', 'v1');
        if (method_exists($this, $version)) {
            return $this->$version($request);
        }
        throw new \Exception('Method not found', 404);
    }

    public function v1(Request $request)
    {
        return "Create User v1";
    }

    public function v2(Request $request)
    {
        return "Create User v2";
    }
}
1个月前 评论
讨论数量: 21

:joy: 貌似每次迭代都新增版本这样并不好吧? 可以不用设计成版本/+路由的方式,可以通过header传递版本号,通过版本号去判断去执行对应控制器。

1个月前 评论
yalng (楼主) 1个月前
MArtian 1个月前
MArtian 1个月前
yalng (楼主) 1个月前
springlee (作者) 1个月前
  1. APP多版本控制,也不是迭代一个需求就增加一个版本的接口,业务链路发生较大改变才会出新版本接口,小版本都只是在原有的接口上横向扩展或兼容处理,多版本控制建议将版本号放在路由上,语义化强且接口独立性好,放在header中,还要做header处理分发路由,也比较麻烦,另外一般的App设计,都需要App传递客户端版本号,服务端版本放在header中与客户端版本有语义冲突。
  2. 如果权限控制不限制版本,在权限验证路由时,判断前缀是否为v*版本号开头,如果是直接替换为空就好了,这样权限基本不用动。
1个月前 评论
  • 这样可否
//  api.php
Route::get('/user/create', [\App\Http\Controllers\User\CreateController::class, '__invoke']);
// User/CreateController.php
<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class CreateController extends Controller
{
    public function __invoke(Request $request)
    {
        $version = $request->header('version', 'v1');
        if (method_exists($this, $version)) {
            return $this->$version($request);
        }
        throw new \Exception('Method not found', 404);
    }

    public function v1(Request $request)
    {
        return "Create User v1";
    }

    public function v2(Request $request)
    {
        return "Create User v2";
    }
}
1个月前 评论

不要变路由,可以加参数version 版本号,接口通过这个版本号判断走哪个方法,版本号存在且大于xx版本走新方法,旧的没有版本号字段就走旧的方法,因为有些用户是基本不升级app的,除非你弹窗强制升级,否则不能使用

1个月前 评论
yalng (楼主) 1个月前
伽蓝幻梦 (作者) 1个月前
伽蓝幻梦 (作者) 1个月前
yalng (楼主) 1个月前
yalng (楼主) 1个月前
伽蓝幻梦 (作者) 1个月前
yalng (楼主) 1个月前

痛苦, 只要迭代的久,那么可能会发现 改一个逻辑, 会修改N个版本的方法

1个月前 评论
yalng (楼主) 1个月前
  1. 在controller方法里,根据版本做一些兼容,简单就直接controller里加版本控制,复杂的,新建一个method,然后根据版本在老的method里,return 到新的

2.controller里,建立方法 method,mthodV2,mthodV3, 然后改造app的调用方法,根据客户端的上报的version 自动调用当前的version或是比他小的version版本

file 如果是这种方法,如果一个BUG,是很久才发现,你会死的很难看。【除非你有足够的开发和测试人员】

1个月前 评论
yalng (楼主) 1个月前

我们现在采用的是1,好处就是维护成本很小,坏处代码多了很多版本判断的逻辑

file

1个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!