refactor(routes): canonical URLs now match sablog format exactly
Build and Deploy / verify (push) Successful in 1m6s
Build and Deploy / deploy (push) Successful in 41s

- /show-{id}.shtml (comments page: /show-{id}-{page}.shtml)
- /category-{cid}.shtml / /category-{cid}-{page}.shtml
- /archives-{YYYYMM}.shtml / /archives-{YYYYMM}-{page}.shtml
- /tag/{name}, /tagslist.shtml, /index-{page}.shtml
- slug 时代的 /posts/{slug} 等旧格式全部 301 到 sablog 格式
This commit is contained in:
2026-09-09 21:21:07 +00:00
parent f6a9a8ea50
commit f5987e7cc2
22 changed files with 113 additions and 70 deletions
+49 -23
View File
@@ -31,38 +31,77 @@ Route::get('/', function () {
return app(HomeController::class)->index();
})->name('home');
Route::get('/posts/{slug}.shtml', [PostController::class, 'show'])->where('slug', '[^/]+')->name('posts.show');
Route::get('/posts/{slug}', fn (string $slug) => redirect()->route('posts.show', $slug, 301))->where('slug', '[^/]+');
// sablog 首页分页格式:/index-{page}.shtml
Route::get('/index-{page}.shtml', function (string $page) {
\Illuminate\Pagination\Paginator::currentPageResolver(fn () => max(1, (int) $page));
return app(HomeController::class)->index();
})->whereNumber('page');
Route::get('/posts/{slug}.shtml', function (string $slug) {
$post = \App\Models\Post::query()->where('slug', $slug)->orWhere('id', (int) $slug)->first();
return $post ? redirect()->route('posts.show', $post->id, 301) : abort(404);
})->where('slug', '[^/]+');
Route::get('/posts/{slug}', function (string $slug) {
$post = \App\Models\Post::query()->where('slug', $slug)->orWhere('id', (int) $slug)->first();
return $post ? redirect()->route('posts.show', $post->id, 301) : abort(404);
})->where('slug', '[^/]+');
// 文章正典:与 sablog 完全一致 /show-{id}.shtml(评论分页 /show-{id}-{page}.shtml
Route::get('/show-{id}.shtml', [PostController::class, 'show'])->whereNumber('id')->name('posts.show');
Route::get('/show-{id}-{page}.shtml', [PostController::class, 'show'])->whereNumber('id')->whereNumber('page');
Route::post('/posts/{post}/comments', [CommentController::class, 'store'])->name('comments.store');
// 浏览量统计(独立端点,避开整页缓存,保证实时)
Route::get('/track-view/{post}', fn (\App\Models\Post $post) => response($post->increment('views') ? '' : '', 204))->name('track-view');
Route::get('/category/{slug}.shtml', [CategoryController::class, 'show'])->where('slug', '[^/]+')->name('category.show');
Route::get('/category/{slug}', fn (string $slug) => redirect()->route('category.show', $slug, 301))->where('slug', '[^/]+');
Route::get('/category/{slug}.shtml', function (string $slug) {
$category = \App\Models\Category::query()->where('slug', $slug)->orWhere('id', (int) $slug)->first();
return $category ? redirect()->route('category.show', $category->id, 301) : abort(404);
})->where('slug', '[^/]+');
Route::get('/category/{slug}', function (string $slug) {
$category = \App\Models\Category::query()->where('slug', $slug)->orWhere('id', (int) $slug)->first();
return $category ? redirect()->route('category.show', $category->id, 301) : abort(404);
})->where('slug', '[^/]+');
// 分类正典:/category-{cid}.shtml(分页 /category-{cid}-{page}.shtml
Route::get('/category-{cid}.shtml', [CategoryController::class, 'show'])->whereNumber('cid')->name('category.show');
Route::get('/category-{cid}-{page}.shtml', [CategoryController::class, 'show'])->whereNumber('cid')->whereNumber('page');
Route::get('/archives.shtml', [ArchiveController::class, 'index'])->name('archives');
Route::get('/archives', fn () => redirect()->route('archives', [], 301));
Route::get('/archives/{year}/{month}.shtml', [ArchiveController::class, 'month'])
->where(['year' => '\d{4}', 'month' => '\d{2}'])
->name('archives.month');
Route::get('/archives/{year}/{month}', fn (string $year, string $month) => redirect()->route('archives.month', [$year, $month], 301))
Route::get('/archives/{year}/{month}.shtml', fn (string $year, string $month) => redirect()->route('archives.month', $year.$month, 301))
->where(['year' => '\d{4}', 'month' => '\d{2}']);
Route::get('/archives/{year}/{month}', fn (string $year, string $month) => redirect()->route('archives.month', $year.$month, 301))
->where(['year' => '\d{4}', 'month' => '\d{2}']);
// 按月归档正典:/archives-{YYYYMM}.shtml(分页 /archives-{YYYYMM}-{page}.shtml
Route::get('/archives-{date}.shtml', [ArchiveController::class, 'month'])->where('date', '\d{6}')->name('archives.month');
Route::get('/archives-{date}-{page}.shtml', [ArchiveController::class, 'month'])->where(['date' => '\d{6}', 'page' => '\d+']);
Route::get('/tags.shtml', [TagController::class, 'index'])->name('tags');
// 标签正典:/tag/{name}sablog 原版);列表 /tagslist.shtml
Route::get('/tagslist.shtml', [TagController::class, 'index'])->name('tags');
Route::get('/tagslist-{page}.shtml', [TagController::class, 'index'])->whereNumber('page');
Route::get('/tag/{name}', [TagController::class, 'show'])->name('tags.show');
Route::get('/tags.shtml', fn () => redirect()->route('tags', [], 301));
Route::get('/tags', fn () => redirect()->route('tags', [], 301));
Route::get('/tags/{slug}.shtml', [TagController::class, 'show'])->where('slug', '[^/]+')->name('tags.show');
Route::get('/tags/{slug}.shtml', fn (string $slug) => redirect()->route('tags.show', $slug, 301))->where('slug', '[^/]+');
Route::get('/tags/{slug}', fn (string $slug) => redirect()->route('tags.show', $slug, 301))->where('slug', '[^/]+');
Route::get('/search.shtml', [SearchController::class, 'index'])->name('search');
Route::get('/search', fn () => redirect()->route('search', [], 301));
Route::get('/search-{page}.shtml', [SearchController::class, 'index'])->whereNumber('page');
Route::get('/links.shtml', [LinkController::class, 'index'])->name('links');
Route::get('/links', fn () => redirect()->route('links', [], 301));
Route::get('/comments.shtml', [CommentController::class, 'index'])->name('comments');
Route::get('/comments', fn () => redirect()->route('comments', [], 301));
Route::get('/comments-{page}.shtml', [CommentController::class, 'index'])->whereNumber('page');
Route::get('/login.shtml', [AuthController::class, 'showLogin'])->name('login');
Route::get('/login', fn () => redirect()->route('login', [], 301));
@@ -109,29 +148,16 @@ Route::get('/themes/{theme}/assets/{path}', [ThemeAssetController::class, 'show'
Route::get('/show-{id}-{page}.html', [LegacyController::class, 'showRewritten'])
->where(['id' => '\d+', 'page' => '\d+']);
Route::get('/show-{id}.html', [LegacyController::class, 'showRewritten'])->where('id', '\d+');
Route::get('/show-{id}-{page}.shtml', [LegacyController::class, 'showRewritten'])
->where(['id' => '\d+', 'page' => '\d+']);
Route::get('/show-{id}.shtml', [LegacyController::class, 'showRewritten'])->where('id', '\d+');
Route::get('/category-{cid}-{page}.html', [LegacyController::class, 'categoryRewritten'])
->where(['cid' => '\d+', 'page' => '\d+']);
Route::get('/category-{cid}.html', [LegacyController::class, 'categoryRewritten'])->where('cid', '\d+');
Route::get('/category-{cid}-{page}.shtml', [LegacyController::class, 'categoryRewritten'])
->where(['cid' => '\d+', 'page' => '\d+']);
Route::get('/category-{cid}.shtml', [LegacyController::class, 'categoryRewritten'])->where('cid', '\d+');
Route::get('/archives-{date}-{page}.html', [LegacyController::class, 'archivesRewritten'])
->where(['date' => '\d+', 'page' => '\d+']);
Route::get('/archives-{date}.html', [LegacyController::class, 'archivesRewritten'])->where('date', '\d+');
Route::get('/archives-{date}-{page}.shtml', [LegacyController::class, 'archivesRewritten'])
->where(['date' => '\d+', 'page' => '\d+']);
Route::get('/archives-{date}.shtml', [LegacyController::class, 'archivesRewritten'])->where('date', '\d+');
Route::get('/tagslist-{page}.html', fn () => redirect()->route('tags', [], 301))->where('page', '\d+');
Route::get('/tagslist.html', fn () => redirect()->route('tags', [], 301));
Route::get('/tagslist-{page}.shtml', fn () => redirect()->route('tags', [], 301))->where('page', '\d+');
Route::get('/tagslist.shtml', fn () => redirect()->route('tags', [], 301));
Route::get('/comments-{page}.html', fn () => redirect()->route('comments', [], 301))->where('page', '\d+');
Route::get('/comments-{page}.shtml', fn () => redirect()->route('comments', [], 301))->where('page', '\d+');
Route::get('/search-{page}.html', fn () => redirect()->route('search', [], 301))->where('page', '\d+');
Route::get('/search-{page}.shtml', fn () => redirect()->route('search', [], 301))->where('page', '\d+');
Route::get('/reg.shtml', fn () => redirect()->route('register', [], 301));
Route::get('/tag/{name}', [LegacyController::class, 'tagByName']);