【问题标题】:Following REST routes based on conditions根据条件遵循 REST 路由
【发布时间】:2014-07-17 10:48:48
【问题描述】:

背景:我正在开发一款需要客户端-服务器通信的回合制游戏。客户端通过 HTTPS 使用 RESTful 请求,服务器使用 JSON 响应。我没有使用 REST 是因为我需要公开 API,而是因为 REST 范式很适合理清客户端/服务器交互。服务器是用PHP编写的。

为了帮助我路由 REST 请求,我一直在寻找有用的路由库。可用的数量惊人,但我很难找到适合我特定需求的。我的问题是:只有在满足某些条件的情况下,才应允许玩家遵循某些路线。显然,我可以检查在路由匹配后调用的方法中是否满足条件,但这似乎是一种容易出错的方法,因为许多路由的条件都是相同的。首先进行部分匹配,然后确定必须满足一些条件才能在部分匹配下遵循更具体的路线会简单得多。

为了说明,游戏中有 4 个级别的“身份验证”:

  1. 未通过身份验证
  2. 验证为 {id}(我们知道它是哪个播放器)
  3. 身份验证为 {id} 并参与会话 {sesid}
  4. 验证为 {id},参与会话 {sesid},轮到玩家了

现在假设身份验证发生在后台。您可以在每个级别逐步遵循的路线:

1 级:

  • 发布\玩家-注册

2 级:

  • PUT \Players\{id} - 更改个人资料
  • GET \Players\{id}\Sessions - 获取会话列表
  • POST \Players\{id}\Sessions - 创建会话
  • POST\Players\{id}\Inventory - 购买物品
  • PUT \Players\{id}\Invites\{sesid} - 加入会话邀请
  • DELETE \Players\{id}\Invites\{sesid} - 拒绝会话邀请

3 级:

  • GET \Players\{id}\Sessions\{sesid} - 获取会话状态
  • DELETE \Players{id}\Sessions\{sesid} - 取消会话

第 4 级:

  • PUT \Players\{id}\Sessions\{sesid}\... - 设置多个会话状态参数

所以我希望在匹配下一组路线之前先检查一些参数。我花了很多时间在 Google 和 Packagist 上寻找合适的路由包(我查看了 Klein、Zend、PHP-Router、Fat_free、Slim、TORO、Aura、FlightPHP、Phalcon、FuelPHP 等文档) 但几乎所有库都要求您预先定义路由并一次性找到一个匹配项 - 有时允许您设置顺序,有时从最具体到最不具体,但大多数情况下只执行一个路由。

如果我可以按定义的顺序进行部分路由匹配,我会有所帮助 - 例如,任何以 player\{id} 开头的路由首先检查身份验证,当它不存在时退出,同时继续检查下一个模式如果身份验证正常,则按定义的顺序。

任何允许我在现场匹配和执行路由的路由库也会有所帮助 - 只要它可以进行部分匹配,以便我可以获取检查身份验证级别要求所需的参数(id、sesid) .显然,为了保持精简,我更喜欢不属于更大框架的库。

从我在 Packagist 阅读的文档页面中,我很难确定是否可以部分匹配某些库中的路由 - 匹配参数,是的,但是路由? - 有时不清楚找到的第一个匹配项是否是唯一匹配项。有什么指点吗?

或者我在这里错过了一个更直接的解决方案?

【问题讨论】:

  • 最好的选择是自己编写或找到一个接近您需求的框架,然后进行更改。
  • 我有点同意这种观点,但我对 PHP 还很陌生——这就是为什么我希望用一个库来解决它(我将使用几个——PHP 就是这样一个时代那些庞大的软件包库的胜利者),而不是自己编写;更不用说钻研其他开发人员的代码库了。我对过滤掉部分 URI、将模式作为值匹配、对结果进行一些验证然后将它们作为参数传递给方法的字符串例程并不完全满意。
  • 我确信使用 Slim,您可以使用 RegEx 来匹配 URL,因此虽然它并不理想并且可能最终看起来有点难看,但它可能会对您有所帮助。
  • 谢谢,但根据文档,Slim 只对第一个匹配项起作用。我首先需要检查部分匹配以验证身份验证级别,然后按此顺序继续进行更具体的匹配。

标签: php rest routing


【解决方案1】:

首先,Klein 将允许您为同一个回调执行多个路由,如下所示:

// This route matches everything
$klein->respond('*', function ($request, $response, $service) { myAuthFunction($request); });
//other routes
// This route matches only a specific path
$klein->respond('GET', '/Players/[i:id]/Sessions', function ($request, $response, $service) { echo "This is the Sessions page for User ID $request->id"; })

查看routing 部分,并滚动到以“注释”开头的段落。如果我没记错的话,路由是按照它们声明的顺序执行的,所以你捕获所有用于检查凭据的路由都需要在更具体的路由之前。

在你的 auth 函数中,你需要抛出一个异常,以防止后面的路由被运行,然后捕获它。 This link 展示了如何捕获 throw HTTP 错误。要抛出一个,只需在回调中调用$router->abort(404)。您必须使用 use 发送 $router (您的 Klein 实例),因此您的回调实际上是:

$klein->respond('*', function ($request, $response, $service) use ($klein) { myAuthFunction($request); });

还有一个路由namespace 系统,我看过,但我自己没用过,但可能对你想做的事情有帮助。

最后,我最终做的是将我的操作分组到控制器中,并在控制器的构造函数中进行权限检查。如果您认为它与您无关,我不想浪费大量时间来解释如何设置它,但我可以根据要求提供更多详细信息。

最后一点,文档说像这样安装 Klein:

php composer.phar require klein/klein v2.0.x

但我发现 dev-master 代码效果更好,所以我建议这样做:

php composer.phar require klein/klein dev-master

希望有帮助!

【讨论】:

  • 非常感谢!看起来我在浏览 Klein 文档时忽略了注释。你的例子有很大帮助。关于控制器,我考虑过这一点,但发现按权限将操作分组到控制器中很麻烦。我现在去试试克莱恩。 :)
  • 我真的很享受与 Klein 相处的经历。代码写得很好,API 既简单又强大。它可以很好地完成它需要做的事情,而无需告诉你该做什么。希望它也能满足您的需求。如果您遇到任何问题,开发人员非常乐意回答 GitHub 存储库上的问题。我还尝试关注 SO 和 GitHub 上与 Klein 相关的问题。最后,不要害怕深入研究代码。这是一个小而写得很好的项目,我从做同样的事情中学到了很多东西。享受吧!
  • 会做,听起来像个守门员。感谢您的建议,非常感谢。
猜你喜欢
  • 2019-02-22
  • 2020-11-06
  • 2019-09-21
  • 1970-01-01
  • 2020-05-06
  • 2018-05-11
  • 1970-01-01
  • 2013-10-08
相关资源
最近更新 更多