Files
laralog/routes/web.php
T
ak 8f1ff6e3f9 feat: 外链中转 /go——点击统计 + 拦截 + 隐藏真实链接
- redirects 表 + UrlRedirector:go_url() 站外链接改写为 /go/{hash}(确定性 hash、同 URL 复用、并发安全、缓存)
- /go/{hash} 302 跳转 + 点击计数 + 最后点击时间;停用状态 410(二次拦截);后台「外链中转」资源可查看点击量/启停/删除
- 接入点:正文外链(渲染器统一改写)、评论正文自动链接(comment_body)、评论作者网址、友链(侧边栏+友链页);站内/相对/mailto/tel/锚点不中转
- 测试 6 个(改写/计数/拦截/复用/渲染/评论正文);README 补充
2026-08-13 01:28:10 +08:00

136 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Blog\Controllers\ArchiveController;
use App\Blog\Controllers\AuthController;
use App\Blog\Controllers\CategoryController;
use App\Blog\Controllers\CommentController;
use App\Blog\Controllers\FeedController;
use App\Blog\Controllers\GoController;
use App\Blog\Controllers\HomeController;
use App\Blog\Controllers\LegacyController;
use App\Blog\Controllers\LinkController;
use App\Blog\Controllers\PostController;
use App\Blog\Controllers\SearchController;
use App\Blog\Controllers\TagController;
use App\Blog\Controllers\ThemeAssetController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| 前台规范路由(canonical 带 .shtml 后缀,无后缀版本 301 兼容)
|--------------------------------------------------------------------------
*/
// 首页:兼容老式 /?action=xxx 查询串(301
Route::get('/', function () {
if (request()->filled('action')) {
return app(LegacyController::class)->resolveAction(request());
}
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', '[^/]+');
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');
// 外链中转:/go/{hash} 302 跳转,记录点击量;停用状态返回 410
Route::get('/go/{hash}', [GoController::class, 'show'])->name('go.show');
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('/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))
->where(['year' => '\d{4}', 'month' => '\d{2}']);
Route::get('/tags.shtml', [TagController::class, 'index'])->name('tags');
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}', 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('/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('/login.shtml', [AuthController::class, 'showLogin'])->name('login');
Route::get('/login', fn () => redirect()->route('login', [], 301));
Route::post('/login.shtml', [AuthController::class, 'login']);
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout.shtml', [AuthController::class, 'logout'])->name('logout');
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/register.shtml', [AuthController::class, 'showRegister'])->name('register');
Route::get('/register', fn () => redirect()->route('register', [], 301));
Route::post('/register.shtml', [AuthController::class, 'register']);
Route::post('/register', [AuthController::class, 'register']);
Route::get('/profile.shtml', [AuthController::class, 'profile'])->middleware('auth')->name('profile');
Route::get('/profile', fn () => redirect()->route('profile', [], 301))->middleware('auth');
/*
|--------------------------------------------------------------------------
| 稳定路径:RSS / Sitemap / Robots
|--------------------------------------------------------------------------
*/
Route::get('/rss.xml', [FeedController::class, 'rss'])->name('feed.rss');
Route::get('/rss.php', [FeedController::class, 'rss']);
Route::get('/sitemap.xml', [FeedController::class, 'sitemap'])->name('feed.sitemap');
Route::get('/robots.txt', [FeedController::class, 'robots'])->name('robots');
/*
|--------------------------------------------------------------------------
| 主题资产(开发模式直接流式返回;生产可用 theme:publish 后由 Web 服务器托管)
|--------------------------------------------------------------------------
*/
Route::get('/themes/{theme}/assets/{path}', [ThemeAssetController::class, 'show'])
->where('path', '.*')
->name('theme.assets');
/*
|--------------------------------------------------------------------------
| sablog 老 URL 兼容(301
|--------------------------------------------------------------------------
*/
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('/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('/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('/tagslist-{page}.html', fn () => redirect()->route('tags', [], 301))->where('page', '\d+');
Route::get('/tagslist.html', fn () => redirect()->route('tags', [], 301));
Route::get('/comments-{page}.html', fn () => redirect()->route('comments', [], 301))->where('page', '\d+');
Route::get('/search-{page}.html', fn () => redirect()->route('search', [], 301))->where('page', '\d+');
Route::get('/reg.shtml', fn () => redirect()->route('register', [], 301));
Route::get('/tag/{name}', [LegacyController::class, 'tagByName']);
Route::get('/index.php', fn () => app(LegacyController::class)->resolveAction(request()));
// 旧 PHP 入口
Route::get('/sitemap.php', fn () => redirect()->route('feed.sitemap', [], 301));
Route::get('/attachment.php', [LegacyController::class, 'attachment']);
Route::post('/post.php', [LegacyController::class, 'postAction']);
Route::get('/tburl.php', fn () => abort(410, 'trackback 已废弃'));
Route::get('/trackback.php', fn () => abort(410, 'trackback 已废弃'));