【问题标题】:Forwarding a request via middleware in Laravel在 Laravel 中通过中间件转发请求
【发布时间】:2019-01-29 14:43:57
【问题描述】:

在其他框架中,存在请求转发的概念,即请求可以在内部重定向到应用程序内的另一个控制器操作,而无需通过显式重定向响应用户。

对于电子商务示例,如果产品的 SEO 友好 URL 为 /red-shoes.html,则对该 URL 的请求将在内部转发到 /catalog/product/id/1234。用户将收到 200 响应代码,并且产品 ID 1234 的产品页面将呈现在 /red-shoes.html 的原始 URL。我试图避免的行为是发出 301 重定向到 /catalog/product/view/id/1234 并丢失友好的 URL。

如何在 Laravel (5.7) 中实现这一点?我可以引入一个中间件来拦截请求,但是在中间件中,我只能在应用程序内进行重定向。 redirect() 将 302 发送回用户,这是我想要的。

namespace App\Http\Middleware;

use Closure;
use App\Rewrite;

class ProductForward
{
    public function handle($request, Closure $next)
    {
        // make a lookup to see if URI in request matches a known product
        $productId = Product::lookupRequest($request);
        if ($productId) {  // if matches, forward to product controller
            return redirect()->route('catalog_product', ['id' => $productId]);  // not desired
        }
        // if no match is found, continue on with the request
        return $next($request);
    }
}

作为后续,如果没有路由匹配,是否可以在路由完成后执行此查找?

例如,假设存在路由/login 以呈现登录页面。如果用户转到/login,则没有必要为此请求查找产品友好的 URL - 只需呈现登录页面。但是,如果用户访问/blue-shoe.html,并且这不是 Laravel 中的预定义路由,则执行产品查找并转发 after 应用程序路由但 before 呈现 404 .

【问题讨论】:

    标签: php laravel


    【解决方案1】:

    对 SEO 友好的 URL 是否可以位于 products/red-shoes 之类的部分中?

    然后,您可以使用Route::get('products/{seoName}'); 之类的参数创建一个路由,这将导致您用于处理/catalog/product/view/id/1234 之类的请求的同一控制器。在那里,您可以解决并发现使用产品 ID 或 seo 名称达到了控制器的操作,并显示匹配的产品。

    基本上,您可以有两条路线products/red-shoes/catalog/product/view/id/1234,它们将显示同一页面,而无需重定向。

    控制器动作

    另外,您可以直接从中间件执行控制器方法。

    而不是调用

    return redirect()->route('catalog_product', ['id' => $productId]);

    你可以运行类似的东西

    return app('App\Http\Controllers\ProductController')->show($productId);

    然后你会得到一个没有重定向的产品页面的内容。

    后备路线

    为了防止在每个请求上运行中间件,您可以使用回退路由。

    Route::fallback(function () {
        //
    });
    

    只有当请求不匹配任何已注册的路由时,才会执行回退路由。您可以在那里搜索产品,如果没有,则返回 404 响应。

    所以你会得到这样的东西:

    Route::fallback(function ()
    {
        // make a lookup to see if URI in request matches a known product
        $productId = Product::lookupRequest(request());
        if ($productId) {  // if matches, forward to product controller
            return app('App\Http\Controllers\ProductController')->show($productId);
        }
        abort(404);
    }
    

    后备路由应在您的文件中最后注册。

    更多信息https://laravel.com/docs/5.7/routing#fallback-routes

    【讨论】:

    • 很遗憾没有。我们正在从另一个系统迁移,该系统有数千个需要维护的现有 URL。
    • @ToddM,明白了。您可以尝试使用中间件中的控制器方法,检查答案的更新。
    • 认为这应该适用于第一部分。关于后续作品的想法?
    • @ToddM 您可以使用后备路由。我更新了答案。
    猜你喜欢
    • 2019-02-08
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-17
    • 1970-01-01
    相关资源
    最近更新 更多