PHP Slim-3:如何在内部重定向到另一条路由

PHP Slim-3: How to redirect internally to another route

我有一条如下所示的通用路线 -

$app->map(['GET', 'POST'], "/", function (\Slim\Http\Request $request, \Slim\Http\Response $response) use ($app) {
    // Some random version 1 processing here ...
}

我有一个 v2 版本,如下所示 -

$app->map(['GET', 'POST'], "/api/v2", function (\Slim\Http\Request $request, \Slim\Http\Response $response) use ($app) {
    // Some random version 2 processing here ...
}

我有问题要解决 -

前端总是命中 API 的 v1(通用路由)。我需要根据参数 appversion 的值在内部重定向到 v2。

如何在不向客户端发回 302 重定向 headers 的情况下在 slim 框架路由中执行此操作?基本上,我需要在内部重定向到服务器本身。

注意:我知道 Nginx 和 Apache 重写。让我们把它们放在一边,将范围限制在 slim framework 路由本身。

您需要抽象化您的调用并创建控制器(即您的代码不会那么精简)。

示例:


function doV2() {
    // ... do V2 things
}
function doV1() {
    // ... do V1 things
}

$app->map(['GET', 'POST'], "/", function (\Slim\Http\Request $request, \Slim\Http\Response $response) use ($app) {
    if($app->request()->params('appversion') === 'v2') return doV2();
    doV1();
}
$app->map(['GET', 'POST'], "/api/v2", function (\Slim\Http\Request $request, \Slim\Http\Response $response) use ($app) {
    doV2();
}

你不能在内部 'redirect' 的原因是你的 'controllers' 是匿名闭包,所以你无法 name/reference/call 它们。相反,如果您将它们抽象为函数(是的,您可能还需要传入 $request/$response),那么您已经命名了可以为适当的路由调用的方法。

除了定义闭包或函数,您还可以定义控制器并在路由器中使用 SlimPHP 的容器解析 - 有一个很好的例子 in the router docs

最后,您 可以 使用中间件来改变基于您的 appversion 参数发生的事情,具体取决于您想要实现的目标的复杂性。

我会在单个路由定义中使用 optional segments

use Psr\Http\Message\{
    ServerRequestInterface as Request,
    ResponseInterface as Response
};

$app->map(['GET', 'POST'], '/[{v2:api/v2}]', function (Request $request, Response $response, array $args) {
    if (isset($args['v2'])) { // You may also check $request->getAttribute('appversion')
        // Version 2 processing here...

        // return $response;
    }

    // Version 1 processing here...

    // return $response;
});

你想要实现的在技术上是可行的,但对我来说,你的问题背后的原因似乎是你想引入你的 API 的新版本,但你不想(或者你不能)更新前端调用新版本,相反,你想在后端处理这个。

如果您要根据 appversion 而不是命中的端点来决定需要调用 API 的哪个版本,那么定义 [=12= 的好处是什么? ] 和 v2 个端点?

如果有人呼叫您的 v1 端点,他们需要您的 v1 响应,如果有人需要您的 v2 响应,他们必须呼叫您的 v2 端点。如果您 return 对 v1v2 端点的响应相同,那么您基本上是在更新 v1 端点行为。

无论如何,您想在另一个路由回调中分派另一个路由,这里是一个完整的示例,展示了如何使用 subRequest:

<?php
require 'vendor/autoload.php';

$app = new \Slim\App;

$app->map(['GET', 'POST'], '/v1', function($request, $response) use ($app) {
    // Get the appversion query parameter and make the decision based on its value
    $appVersion = $request->getParam('appversion');
    if($appVersion == '1.0') {
        return $app->subRequest($request->getMethod(), '/v2',
            http_build_query($request->getQueryParams()),
            $request->getHeaders(),
            $request->getCookieParams(),
            $request->getBody()->getContents()
        );
    }
    return 'API version: v1, appversion: ' . $appVersion;
});

$app->map(['GET', 'POST'], '/v2', function($request, $response) {
    return 'API version: v2, request method: ' . $request->getMethod() .', appversion: '. $request->getParam('appversion') . ', body: <pre>' . print_r($request->getParsedBody(), 1);
});

$app->get('/form', function() {
return <<<form
    <form method="POST" action="/v1?appversion=1.0">
        <input type="text" name="foo" value="bar">
        <button type="submit" value="submit">Submit</button>
    </form>
form;
});

$app->run();

现在,如果您尝试达到 /v1?appversion=1.0,来自 /v2 回调的响应将被 returned。尝试达到 /v1appversion 等于任何其他值(例如 /v1?appversion=2.0)会导致应用程序 return v1 响应。

subRequest 方法也可以处理 POST 请求。请参考method documentation in Slim code repository。该示例提供了一个 /form URI 来证明这一点。