【发布时间】:2015-09-26 12:12:30
【问题描述】:
我正在使用 Laravel 5(具体来说,“laravel/framework”版本是“v5.0.27”),会话驱动程序 = 'file'。
我正在 Windows 7 64 位机器上开发。
我注意到有时(大约一周一次)我会意外地随机退出。有时甚至在我登录后立即发生这种情况。我已将日志消息添加到我的身份验证逻辑代码中,但未触发日志代码。 Laravel 表现得好像完全丢失了会话文件。
另一个更严重的问题是,有时在调试会话后(使用 xdebug 和 Netbeans),Laravel 开始丢失其他文件 - .env 设置、一些调试栏 JS 文件等。错误日志包含如下消息:
[2015-07-08 13:05:31] local.ERROR: exception 'ErrorException' with message 'mcrypt_encrypt(): Key of size 7 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported' in D:\myproject\vendor\laravel\framework\src\Illuminate\Encryption\Encrypter.php:81
[2015-07-08 13:05:31] local.ERROR: exception 'PDOException' with message 'SQLSTATE[HY000] [1044] Access denied for user ''@'localhost' to database 'forge'' in D:\myproject\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php:47
这清楚地表明 .env 文件未被 Laravel 读取,因此它使用默认设置:
'database' => env('DB_DATABASE', 'forge'),
'key' => env('APP_KEY', 'somekey'),
文件丢失很少发生,可能一个月左右一次,而且总是在调试会话之后发生。我总是必须重新启动 Apache 才能让它再次工作。
为了对系统进行压力测试并可靠地重现问题,我在我的 Angular 控制器中使用了一个快速破解:
setInterval(function(){
$scope.getGridPagedDataAsync();
}, 500);
这只是从 Angular 到 Laravel 的一个基本数据请求。
就是这样 - 现在我可以在 3 分钟或更短的时间内重现会话丢失和 .env 丢失。
我之前在同一台 PC 上使用相同的 Apache+PHP 开发了 AJAX 密集型 Web 应用程序,但没有 Laravel,没有 .env,而且我之前没有注意到此类问题。
通过代码调试时,我发现 Laravel 根本没有使用 PHP 内置会话,而是实现了自己的基于文件的会话。显然,它没有提供与默认 PHP 会话相同的可靠性,我不知道为什么。
当然,在现实生活场景中,我的应用不会是 AJAX 密集型的,但根据我的经验,在某些情况下,只需两个同时发生的 AJAX 请求就足以丢失会话。
我在 Laravel 上看到了一些有关各种会话问题的相关错误报告。不过,我还没有看到任何关于 dot-env 的信息,但它似乎遇到了同样的问题。
我的猜测是 Laravel 不使用文件锁定和等待,因此如果由于某种原因(可能被某些并行进程或 Apache 锁定)无法读取文件,那么 Laravel 就会放弃并返回它可以返回的任何内容。
有什么好的解决办法吗?也许它是特定于 Windows 的,并且问题会在 Linux 机器上消失?
很好奇,为什么 Laravel(或 Symfony)开发人员还没有修复他们的会话文件驱动程序。我知道锁定/等待会减慢速度,但至少有一些选项可以打开“可靠会话”会很棒。
同时我会尝试单步调试 Laravel 代码,看看我是否可以发明一些“快速而肮脏”的解决方案,但最好有一些可靠的“最佳实践”解决方案。
关于 .env 的更新
问题转为与锁定文件无关。我找到了 .env 问题的 Laravel 错误报告,这使我找到了 Dotenv 项目的链接报告,该报告反过来说这是一个核心 PHP 问题。令我不安的是,Dotenv 开发人员说 Dotenv 从未打算用于生产,但 Laravel 似乎依赖于 Dotenv。
在https://github.com/laravel/framework/pull/8187 中,似乎有一个解决方案应该朝一个方向工作,但一些评论者说,在他们的情况下,问题恰恰相反。有人叫 crynobone 给出了一个聪明的代码 sn-p 来尝试:
$value = array_get($_ENV, $key, getenv($key));
在 Dotenv 和 Laravel Githubs 上出现了另一个使用“makeMutable()”的建议,但评论者报告说这可能会破坏测试。
所以我尝试了 crynobone 的代码,但它对我不起作用。在调试时,我发现在我的情况下,当并发请求发生故障时,$key 既无法在 getenv() 中找到,也无法在 $_ENV 中找到,甚至在 $_SERVER 中也找不到。 唯一有效(快速而肮脏的实验)是添加:
静态::$cached[$name] = $value;
到 Dotenv 类,然后在 helpers.php env() 方法中我看到:
Dotenv::$cached[$key]
总是好的,即使 $_ENV 和 getenv 都没有提供任何东西。
虽然 Dotenv 不适合生产,但我不想更改我们的部署和配置工作流程。
接下来我必须调查会话问题...
附录
相关的 Laravel 错误报告(有些甚至来自第 4 版。而且似乎没有修复): https://github.com/laravel/framework/issues/4576
https://github.com/laravel/framework/issues/5416
https://github.com/laravel/framework/issues/8172
还有一篇旧文章阐明了正在发生的事情(至少与会话问题有关): http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/
【问题讨论】:
-
如果一次抛出 100 个非 ajax 请求会发生什么?
-
@itachi:我刚刚运行了
ab -n 10000 -c 100 http://mysite/,并且在 laravel.log 文件中,除了“超过 30 秒的最大执行时间”消息之外,我看到了很多mcrypt_encrypt和SQLSTATE[HY000]消息,这意味着对于许多并发的非 AJAX 请求,该 .env 文件也没有正确加载。 -
这些原来是两个不同的问题 - .env 实际上与锁定文件无关。我找到了 .env 问题的 Laravel 错误报告,这使我找到了 Dotenv 项目的链接报告,该报告反过来说这是一个核心 PHP 问题。令我不安的是,Dotenv 开发人员说 Dotenv 从未打算用于生产,但 Laravel 似乎将 Dotenv 紧密集成到所有环境配置中。所以,我想“解决方案”是为我们的 Laravel 应用程序禁用 Dotenv。
-
我正在使用 laravel5.1 开发 angularjs 应用程序,如果我连续发送许多请求..它会引发 401 异常。我也在使用 windows 和 Apache 服务器
-
@Muhammed Shihabuddeen,是的,这可能是由我正在谈论的会话问题引起的。看来,我设法解决了 Dotenv 问题(请参阅此处的最后一条评论:github.com/vlucas/phpdotenv/issues/76),明天我会看看是否可以对会话问题做任何事情。