自定义路由文件

发布于 作者

Custom Route Files image

有一天早上,我醒来看到 Slack 通知。这可不是什么好兆头。

一夜之间,我的 Redis 实例完全满了。我们使用 Redis 做两件事

  1. 会话存储
  2. 缓存一些数据,没什么实质性的

我使用 TablePlus 查看了 Redis 中的内容。有点难以判断发生了什么,因为 Laravel 使用随机哈希作为缓存键的一部分,并且有效负载是编码/加密的。

但是我可以看到有两个 Redis 数据库(db0db1)。检查 config/databases.php 文件后,我发现确实为 Redis 定义了两个相应的数据库。

# File config/databases.php
return [
// Things ommitted here...
 
 
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
 
'redis' => [
 
'client' => env('REDIS_CLIENT', 'phpredis'),
 
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
 
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
 
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
 
],
];

default 连接使用 db0,而 cache 连接使用 db1。事实证明,会话存储在 db0 中,而我们在代码中缓存的内容使用 db1。默认数据库 db0 的键比缓存数据库多很多。

应用程序正在创建过多的会话.

什么是会话?

每个 Web 请求(针对 routes/web.php 中定义的路由)都会创建一个会话(或使用现有的会话)。Web 应用程序在创建会话时会返回一个 Cookie。Web 浏览器会存储这些 Cookie,并在进行额外的 Web 请求时将 Cookie 发送回服务器。这使我们的 Web 应用程序能够知道哪个会话对给定用户有效。

如果浏览器在每次请求时不返回 Cookie,那么用户将无法保持登录状态。

基于 API 的会话的工作方式不同。每个会话都会在每个 Web 请求中创建,然后销毁 - 不涉及 Cookie。相反,客户端需要在每次 Web 请求时发送其身份验证信息(通常是某种令牌)。

是什么导致 Redis 爆炸?

那么,是什么导致我们的 Redis 实例因会话而爆炸?

动态生成的资产,其他人将其嵌入到自己的网站上。我们有两个这样的情况

  1. 我们的应用程序生成了一个 .js 文件,其他人将其嵌入到他们的网站上
  2. 我们的应用程序还为相同的目的生成了 .svg 图像

这些路由是在我们的 routes/web.php 文件中定义的

Route::get('/embed.js');
Route::get('/{project}/share.js');

你看到问题了吗?客户将这些内容放在他们自己的网站上。每当有人访问他们的网站时,都会向我们的应用程序发出 HTTP 请求以获取嵌入代码或 SVG,**并且这会创建一个会话**。

这意味着我们的客户的网络流量也会在我们的 Web 应用程序中创建会话!

如何减少会话创建

**解决方法是确保我们不会为某些路由创建会话。** 这么说很简单,但是我们该怎么做呢?

事实证明,Cookie 和会话的创建是在 Laravel 的中间件中完成的。这很好,因为我们可以控制为每个路由应用哪些中间件。

为了确保某些路由不会创建会话/返回 Cookie,我喜欢创建一个单独的路由文件,该文件具有不同的中间件堆栈。

为此,我们需要做几件事

  1. 创建一个新的 routes/static.php 文件(名称是任意的)
  2. app/Http/Kernel.php 中添加一个中间件堆栈
  3. 更新 app/Providers/RouteServiceProvider.php 以加载我们的新路由文件,并应用我们的新中间件堆栈

新路由文件很简单 - 我们创建一个新文件并将路由定义移动到其中

# File routes/static.php`
 
# Move these from routes/web.php
Route::get('/embed.js');
Route::get('/{project}/share.js');

然后我们可以更新 Kernel.php 文件以创建一个新的中间件堆栈。我们可以复制 web 中间件堆栈并删除处理 Cookie 和会话的中间件

# File app/Http/Kernel.php
 
# Items omitted here
 
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
 
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
+ 
+ 'static' => [
+ \Illuminate\Routing\Middleware\SubstituteBindings::class,
+ ],
];
 
# Items omitted here

我们创建了一个名为 static 的新中间件组。它类似于 API 中间件,但我们没有节流。

最后,我们需要注册新路由文件,并应用我们的新 static 中间件组。我们将通过更新 RouteServiceProvider.php 来完成此操作

# File app/Providers/RouteServiceProvider.php
 
# Items omitted here
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
 
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
 
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
+ 
+ Route::middleware('static')
+ ->namespace($this->namespace)
+ ->group(base_path('routes/static.php'));
+ });
}
 
# Items omitted here

RouteServiveProvider 注册每个路由文件,并确定其中间件。这就是 routes/web.php 中的每个内容如何获得分配给它的 web 中间件组。

这也是我们创建自己的路由文件的原因 - 我们想避免 web 中间件组,并且能够在需要时将路由添加到新的路由文件中。

结果

结果是,我们的两个“静态”路由(返回动态生成的资产 - JS 文件和 SVG)不再创建会话,也不再返回 Cookie。

这使我们的 Redis 实例得以恢复。随着会话的过期,它们从 Redis 中删除。由于我们的客户流量不再在我们的会话存储中创建会话,因此 Redis 实例再也没有满过!

Chris Fidao photo

CloudCastsServers for Hackers 教授编码和服务器。 Chipper CI 的联合创始人。

Cube

Laravel 新闻稿

加入 40k+ 其他开发者,绝不错过新的技巧、教程等等。

Laravel Forge logo

Laravel Forge

轻松创建和管理您的服务器,并在几秒钟内部署您的 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发者必备的代码运行器。使用 AI、自动完成功能和对本地和生产环境的即时反馈进行调试。

Tinkerwell
No Compromises logo

No Compromises

Joel 和 Aaron,两位来自 No Compromises 播客的经验丰富的开发者,现在可以为您的 Laravel 项目提供服务。 ⬧ 固定费率为 7500 美元/月。 ⬧ 没有冗长的销售流程。 ⬧ 没有合同。 ⬧ 100% 满意退款保证。

No Compromises
Kirschbaum logo

Kirschbaum

提供创新和稳定性,确保您的 Web 应用程序取得成功。

Kirschbaum
Shift logo

Shift

正在运行旧版本的 Laravel?立即使用自动化的 Laravel 升级和代码现代化,使您的应用程序保持新鲜状态。

Shift
Bacancy logo

Bacancy

只需 2500 美元/月,即可使用经验丰富的 Laravel 开发者(拥有 4-6 年的经验)为您的项目注入活力。获得 160 小时的专业知识和 15 天的无风险试用期。立即预约通话!

Bacancy
Lucky Media logo

Lucky Media

立即获得幸运 - Laravel 开发的理想选择,拥有十多年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel 电子商务

Laravel 的电子商务。一个开源软件包,将现代无头电子商务功能的强大功能带入 Laravel。

Lunar: Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 招聘平台

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS 启动工具包

SaaSykit 是一个 Laravel SaaS 启动工具包,包含运行现代 SaaS 所需的所有功能。支付、漂亮的结账、管理面板、用户仪表板、身份验证、即用型组件、统计、博客、文档等等。

SaaSykit: Laravel SaaS 启动工具包
Rector logo

Rector

您无缝升级 Laravel、降低成本和加速创新以帮助企业取得成功的合作伙伴

Rector
MongoDB logo

MongoDB

使用 MongoDB 和 Laravel 的强大集成增强您的 PHP 应用程序,使开发人员能够轻松高效地构建应用程序。 使用熟悉的 Eloquent API 支持事务、搜索、分析和移动用例。 了解灵活、现代的 MongoDB 数据库如何改变您的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的零依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

在您的 Laravel 应用程序中添加 Swagger UI

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel Prompts 构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速、模糊的网站搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 包为您的 Laravel 应用程序添加评论

阅读文章