【问题标题】:Laravel 8 routes to controllers. SEO friendly URL structureLaravel 8 路由到控制器。 SEO友好的URL结构
【发布时间】:2021-01-30 00:20:14
【问题描述】:

我试图弄清楚如何在 Laravel 8 项目中实现特定的 URL 结构以及实现这一目标的必要途径。我想要的是:

// Example urls to listings in the business directory.
// These urls should be routed to the directory controller.
www.domain-name.com/example-business-name-d1.html
www.domain-name.com/example-business-name-d15.html
www.domain-name.com/example-business-name-d100.html
www.domain-name.com/example-business-name-d123.html
www.domain-name.com/example-business-name-d432.html

// Example urls to articles/posts in the blog.
// These urls should be routed to the posts controller.
www.domain-name.com/example-post-name-p5.html
www.domain-name.com/example-post-name-p11.html
www.domain-name.com/example-post-name-p120.html
www.domain-name.com/example-post-name-p290.html
www.domain-name.com/example-post-name-p747.html

// We want to avoid the more traditional:
www.domain-name.com/directory/example-business-name-1.html
www.domain-name.com/blog/example-post-name-5.html

这是因为我们不希望每个列表或博客文章的 URL 中都包含字符串“目录”或“博客”。没有它,搜索引擎结果会更好。

到目前为止,我在 web.php 路由文件的底部使用了一个包罗万象的路由 {any} 来“捕捉所有”的路由。然后我操纵路径提供的字符串以从 url 的末尾获取 ID 和单个字符标记。然后我有了这 2 个变量,但可以弄清楚如何将它们传递给正确的控制器!

还是我真的很笨,有更好的方法来实现这一点?

Route::get('{any}', function($any = null){

    // Break up the url into seperate parts.
    $pieces = explode("-", $any);
    $pieces = array_reverse($pieces);
    $piece =  $pieces[0];

    // Remove the .html
    $piece = substr($piece, 0, -5);

    // Get the two parts of the identifier.
    $id = substr($piece, 1);
    $token = substr($piece, 0, 1);

    // Call correct controller based on the token.
    switch ($token) {
        case "d":
            // HERE I WANT TO PASS THE ID ON TO THE SHOW ACTION OF THE DIRECTORY CONTROLLER 
        break;
        case "p":
            // HERE I WANT TO PASS THE ID ON TO THE SHOW ACTION OF THE POSTS CONTROLLER 
        break;
        default:
            return abort(404);
        break;
    }

});

【问题讨论】:

  • 你能分享你已经拥有的其他路线定义吗?到底为什么需要这么复杂的路由匹配方式?
  • 没有它,搜索引擎结果会更好地工作。 但是,它们会……吗?我很确定“目录”可以帮助搜索引擎了解您的内容的结构和层次结构。
  • Stackoverflow 使用您认为是不好的做法的格式,而且它们似乎总是能在搜索结果中排名靠前
  • 你想使用.html .?在 laravel 中
  • @MartinBean 你是对的。在 URL 中包含“目录”确实有助于描述结构和内容。我仍将其用于目录登陆页面上的 URL 和相关的分页页面。当我说“没有它,搜索引擎结果会更好。”我指的是用户如何查看和解释 SERPS。我认为最好在 Google 显示的 URL 中显示完整的公司名称,如果 URL 中保留“目录”一词,那么公司名称可能会被截断。这是一个边缘点,我想归结为个人喜好。

标签: php laravel url url-routing laravel-8


【解决方案1】:

您可以使用正则表达式匹配 slug

Route::get('/{any}', 'YourController@methodName')->where(['any' => '.*(-d(.*?)\.).*']);

p重复

然后,当您在控制器方法中获取 $site 时,您可以使用正则表达式来获取站点。

public function methodName($site)
{
    preg_match('/.*(-(d(.*?))\.).*/', $site, $parts); //or something similar, $parts[2] will have what you want
}

这会给你的控制器方法 d{number} 或 p{number}

Route::get('/{site}', function($site) {
    $code = preg_match('/.*(-(d(.*?)|p(.*?))\.).*/', $site, $parts) ? $parts[2] : null;

    $controllerName = 'ControllerA';
    if(isset($code) && !is_null($code) && Str::contains($code, 'p')) {
        $controllerName = 'ControllerB';
    }

    $controller = app()->make('App\Http\Controllers\Application\\' . $controllerName);

    return $controller->callAction('methodName', $params = ['code' => $code]);
})->where(['site' => '.*(-(d|p)(.*?)\.).*']);

【讨论】:

    【解决方案2】:

    我会将路径拆分为 2 个变量($slug$id)并直接将其传递给控制器​​。

    Route::get('{slug}-d{id}.html', 'DirectoryController@show')
        ->where(['slug' => '([a-z\-]+)', 'id' => '(\d+)']);
    
    Route::get('{slug}-p{id}.html', 'PostController@show')
        ->where(['slug' => '([a-z\-]+)', 'id' => '(\d+)']);
    

    在你的控制器中

    class DirectoryController
    {
        public function show(string $slug, int $id) {}
    }
    
    class PostController
    {
        public function show(string $slug, int $id) {}
    }
    

    【讨论】:

    • 这显然不适用于任何具有与“example-business-name”和“example-post-name”不同的字符串的网址......
    • 这是一个非常好的解决方案,也许html 有点冗长,虽然呵呵
    • 这对我有用。谢谢。我稍微调整了正则表达式,使其也适用于数字。 ([÷a-z0-9\-]+)。现在适用于我拥有的所有测试公司名称。
    【解决方案3】:

    我可以看到两种实现此结果的方法:

    创建中间控制器

    Route::get('{path}', 'CheckPathController@redirect')
    

    然后在您的CheckPathController 中进行所有检查并调用正确的控制器操作:

    public function redirect(Request $request, $path) {
      // Your checks on $path, extract $id and content type
    
      if($isPost) {
         $controller = resolve(PostController::class);
         return $controller->show($request, $id);
      }
    
      if($isBusiness) {
         $controller = resolve(BusinessController::class);
         return $controller->show($request, $id);
      }
    
      // No matches, error 404
      abort(404);
    }
    

    复杂的正则表达式

    见:https://laravel.com/docs/8.x/routing#parameters-regular-expression-constraints

    我不是正则表达式大师,这应该是匹配任何{word}-{word}-...-p{id}.html 模式的基本方法,但它会在出现意外字符时中断

    Route::get('{path}', 'PostController::show')
       ->where(['path' => '([\w]*-)*p[0-9]+\.html$']);
    
    Route::get('{path}', 'BusinessController::show')
       ->where(['path' => '([\w]*-)*d[0-9]+\.html$']);
    

    请注意,在这种情况下,您的控制器将收到 pull $path 字符串,因此您需要在此处提取 id。

    【讨论】:

      猜你喜欢
      • 2012-10-06
      • 2011-12-24
      • 2011-04-06
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 2012-01-17
      相关资源
      最近更新 更多