如何基于用户订阅类型在React组件展示差异化内容
完全可以用单API路由配合中间件实现这套逻辑,而且比你最初设计的多端点+前端二次请求的方案体验和可维护性都更好。
具体实现方案
路由设计
只需要保留1个统一的专属内容拉取接口即可,比如api/subscription/content,所有订阅档位的用户拉取专属内容都请求这一个接口,前端不需要根据订阅类型拼接不同的请求地址。原有的api/userinfo接口可以保留,用于前端做基础UI差异化判断(比如给不同档位用户展示不同的导航入口、升级提示)。
中间件逻辑
在Laravel中新建订阅识别中间件,核心逻辑不需要前端传任何订阅相关参数,直接从当前登录态的用户信息中读取订阅类型,从根源上避免前端篡改参数越权访问高档位内容的问题:
- 读取当前认证用户的
subscription_type字段,做合法性校验,如果不在预设的三个档位范围内、或者订阅已过期,直接返回403异常 - 将校验通过的订阅类型注入请求上下文,供后续控制器直接调用
参考代码:
// app/Http/Middleware/ResolveSubscription.php public function handle(Request $request, Closure $next) { $user = $request->user(); // 校验订阅类型合法性 if (!in_array($user->subscription_type, ['demo', 'mid', 'extra'])) { abort(403, '订阅状态异常,请联系客服处理'); } // 将订阅类型注入请求属性 $request->attributes->add(['active_sub_type' => $user->subscription_type]); return $next($request); }
写完后在app/Http/Kernel.php中注册这个中间件,绑定到api/subscription/content路由上即可。
控制器查询逻辑
控制器层不需要写多层if/else判断,提前维护好订阅类型和Mongo集合的映射关系,直接根据中间件注入的订阅类型查询对应集合返回数据即可,后续新增订阅档位只需要加一行映射配置,不需要重复写查询逻辑:
参考代码:
// 内容接口控制器方法 public function fetchUserSubContent(Request $request) { // 订阅类型与Mongo集合的映射表 $collectionBind = [ 'demo' => 'demo_user_content', 'mid' => 'mid_user_content', 'extra' => 'extra_user_content' ]; $targetCollection = $collectionBind[$request->attributes->get('active_sub_type')]; // 查询对应集合下当前用户的专属数据 $content = DB::connection('mongodb') ->collection($targetCollection) ->where('user_id', $request->user()->id) ->orderBy('created_at', 'desc') ->get(); return response()->json(['data' => $content]); }
React端适配
前端逻辑会比原方案简单很多:
- 需要做UI差异化的场景(比如Demo用户展示升级横幅、高等级用户展示专属功能入口),直接从
/api/userinfo接口返回的订阅类型字段判断即可 - 拉取渲染内容时,不需要做任何订阅类型判断,进入对应页面直接请求
/api/subscription/content,拿到返回数据直接渲染即可,后续后端调整订阅规则、新增档位,前端这部分逻辑完全不需要改动。
方案对比原设计的优势
- 减少一次冗余HTTP请求:不需要先拉用户信息拿到订阅类型,再发第二次请求拉内容,页面加载速度更快
- 权限安全性更高:订阅类型校验完全在服务端完成,不存在前端篡改请求地址越权拉取高等级内容的风险
- 维护成本更低:后续新增订阅档位只需要在后端加映射配置、新建对应集合即可,不需要新增路由、重复写控制器逻辑,也不需要调整前端请求代码
- 代码冗余更少:三个档位的内容查询逻辑完全复用,不需要为每个档位单独写一套接口代码
注意:如果三类订阅用户返回的内容结构差异极大,也可以在控制器层根据订阅类型调用不同的处理类,依然走同一个路由,不需要拆分端点。
内容的提问来源于stack exchange,提问作者user12240630
相关产品推荐
相关产品推荐

