Cookie会话驱动程序不会保存任何验证错误或闪存数据。

11 浏览
0 Comments

Cookie会话驱动程序不会保存任何验证错误或闪存数据。

我在Laravel中遇到了cookie会话驱动的问题。

我有一个简单的表单,并设置了验证规则。这是保存表单数据的方法:

public function store()
{
    $this->validate(request(), [
        'name'        => 'required',
        'title'       => 'required',
        'description' => 'required|max:600',
        'image'       => 'required|file|mimes:jpeg,png',
    ]);
    $member = TeamMember::create(request()->all());
    $member->addImage(request()->file('image'));
    return redirect()->route('backoffice.team-members');
}

非常简单。

问题是,当使用cookie会话驱动时,如果我保存的表单中的描述超过1024个字符,我将被重定向,但是没有闪存数据和视图中的$errors来处理下一个请求。

例如:

enter image description here

这是在使用以下行之后的POST请求:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce gravida eros ut leo commodo luctus. Nulla neque dui, laoreet quis felis in, porta tincidunt felis. Phasellus in lacus et sem condimentum ornare. Praesent vitae nisi tempus, gravida tortor eu, convallis dui. Cras lacinia posuere scelerisque. Vestibulum tincidunt purus id sollicitudin varius. Sed eros urna, mattis nec nunc eu, finibus suscipit ipsum. Aliquam varius faucibus congue. Vivamus convallis imperdiet sem a commodo. Proin cursus feugiat sem a pharetra. Curabitur rhoncus non quam sit amet lacinia. Sed ut nisl id odio faucibus vehicula vel ut erat. Vestibulum ut iaculis magna. Quisque sit amet massa sodales, suscipit nisl eu, dapibus elit. Morbi posuere ligula pretium commodo semper. Nam odio elit, rutrum finibus tortor eget, viverra viverra metus. Proin tincidunt tempor ex pretium rhoncus. Proin egestas erat sed eros congue, mollis gravida magna bibendum. Pellentesque vel bibendum nunc. Orci varius natoque penatibus et magnis dis viverra fusce.

在描述字段中。准确地说是1024个字节。

相反,如果我只是在字段中填写一些更多的虚拟数据,但不要太过离谱:

enter image description here

如果我将会话驱动程序更改为文件:

enter image description here

...它是可以工作的。

但是这并不能解决我的问题。我确实需要使用cookie会话驱动程序,因为生产网站在3个不同的数据中心运行以实现高可用性。使用cookie会话允许用户访问任何一个服务器,并继续其请求,而无需使用任何粘性会话或任何中央会话驱动程序。

使用数据库作为驱动程序(也是在具有高可用性的集群中)不是一个选择,因为这是一个非常高流量的网站,每个请求都需要写入数据库,这听起来并不吸引人。我希望以任何代价都能避免这种情况。

有办法解决这个问题吗?

我必须说这是网站的后台管理界面,但是很快前端用户也将能够在文本区域中写入超过1024个字符...所以如果只更改后台管理界面的驱动程序是没有帮助的,因为我们的用户也会遇到相同的问题。

0
0 Comments

问题的原因是使用cookie作为会话驱动程序时,浏览器对cookie的大小有限制,太大的cookie无法存储。解决方法是使用redis作为会话驱动程序。以下是解决方法的步骤:

1.安装Redis服务器,并添加predis/predis包:

composer require predis/predis

2.更改配置文件config/database.php

'redis' => [
    'client' => 'predis',
    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
    ],
],

注意,在负载均衡器的情况下,Redis数据库必须集中在特定的服务器上,并且运行laravel的所有节点必须连接到同一个Redis服务器。

0
0 Comments

Cookie session driver won't save any validation error or flash data的问题是由于使用cookie会话驱动程序存储大量数据时不适用。浏览器通常将存储在一个cookie中的数据限制在大约4 KB(4096字节)。正如我们发现的,通过尝试将一个长度为1024个字符的字符串存储在会话cookie中,我们很容易耗尽这个容量。问题中的“Lorem ipsum…”字符串仅包含ASCII字符,并且每个ASCII字符使用4个字节表示,所以1024×4=4096字节。

正如我们所看到的,当我们需要在一个会话cookie中存储其他项目时,例如PHP值的序列化元数据,或者数据包含消耗超过4个字节的UTF-8字符时,我们很快就会耗尽空间。要继续使用cookie存储大于4 KB的会话数据,我们需要编写一个自定义的会话驱动程序,将会话数据分割成多个cookie,并在每个响应中重新组装它们。基于充足的理由,我不知道是否有现有的软件包可以做到这一点。这就引出了我下一个问题...

我强烈不建议使用cookie来存储完整的会话(而不仅仅是会话ID)。这种方法可能会导致安全漏洞,增加请求和响应的开销(包括相同域上静态资源的请求),风险是数据不同步(右键单击应用程序标签→“复制”以查看发生了什么),给测试和调试带来了麻烦,并且在存储某些类型的数据时会引发问题。

对于问题中的分布式应用程序,我们有四个选择:

1. 在每个应用实例中访问的中央服务器上存储会话数据

2. 在每个站点存储会话状态,并在站点之间进行复制

3. 使用“sticky”会话将用户锚定在开始会话后的一个站点

4. 编写大量代码来实现允许客户端传递会话状态而不使用cookie的自定义会话驱动程序,或者分割cookie的会话驱动程序

我认为我们可以合理地排除第四个选项。除非我们有非常好的理由避免使用前三种方法(通常情况下我们通常没有),否则我们无法证明在构建一个系统来在HTTP之间传输会话数据时所需要的工作量,复杂性和开销,而前三个选项是标准、被广泛接受的解决方案。

根据问题中的信息,我认为你已经理解了其他三个选项背后的概念和影响,所以我不会详细解释每个选项的说明(但如果需要,请留言告诉我)。

对于没有高级基础设施要求的应用程序,我推荐使用第三种方法:粘性会话。这些相对容易设置,并且通常需要在负载均衡器上进行配置,以便一旦客户端启动与应用服务器的会话,负载均衡器将在会话结束之前将任何后续请求路由到同一服务器。为了实现高可用性,我们可以将这种方法与Redis会话驱动程序和在数据中心之间进行主从复制的Redis服务器相结合,并且可以选择使用Redis Sentinel自动进行故障转移。Redis非常适合会话数据,并且比关系数据库具有更好的性能。如果我们在每个数据中心有多个应用实例,Redis为该站点的所有实例提供了会话数据的中心位置。

为了完整起见,并直接回答问题,这里是创建处理大于4 KB会话数据的基于cookie的会话驱动程序所需的开发概述。再次强烈建议使用上述其他方法之一:

1. 首先,我们需要创建一个实现PHP的SessionHandlerInterface的新类(可以参考Laravel的cookie会话处理程序作为起点,我们可能可以扩展这个类)。

2. 这个类的write()方法需要对会话数据进行序列化,然后将数据分割成小于4 KB的块(对于某些浏览器,小于4093字节)。请确保考虑到多字节字符。在拆分数据之前,如果会话包含敏感信息或者不希望聪明的用户干扰值,我们可能还想对其进行加密。然后,该方法应为会话数据的每个块添加一个新的cookie。每个cookie都需要在其名称中包含序列,并且我们可以添加一个包含块数的附加cookie。

3. read()方法将以相反的顺序执行这些操作。首先,它将使用包含块数的cookie的值从请求中的cookie中重新组装每个块,然后,如果我们对其进行了加密,可以选择解密数据。

4. destroy()方法应清除包含块的每个cookie的内容。

5. 然后我们将为会话驱动程序选择一个名称,比如cookie-extended,并在服务提供者的boot()方法中使用register it as an available driver进行注册。我们需要在config/session.php或.env中指示应用程序使用新的驱动程序进行用户会话。

如果你决定选择这条道路,请确保在计划支持的每个浏览器中测试实现,因为不同的浏览器对每个域可以接受的cookie的大小和数量都有自己的限制。即使我们增加了可以存储的会话数据量,我们仍然受限于每个域名的浏览器可接受的最大cookie数量。

最后,将会话存储在数据库中可能不会像你想象的那样影响性能。在为可能不是真正问题的问题进行大量优化之前,测量这个简单解决方案所创建的实际负载可能是值得的。

0