当前位置: 首页 > 知识库问答 >
问题:

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

洪飞驰
2023-03-14

我在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个字符,那么我将被重定向回来,但是在视图中没有flash数据,也没有$errors来处理下一个请求。

示例:

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.

...管用。

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

使用数据库作为驱动程序--它也在与HA的集群中--不是一个选项,因为这是一个非常高的流量网站,这将是一个写每个请求听起来一点也不吸引人。我想不惜一切代价防止这种情况发生。

反正这个能解决吗?

我必须说这是网站的后台,但很快前台的用户也将能够在一个文本中写超过1024个字符...因此,如果我只是为backoffice改变驱动程序,这并没有帮助,因为我们会遇到同样的用户。

共有1个答案

林辰钊
2023-03-14

cookie会话驱动程序不适用于必须在用户会话中存储大量数据的应用程序。浏览器通常将存储在一个cookie中的数据限制在4 KB(4096字节)左右。正如我们所发现的,我们可以通过尝试在会话cookie中存储一个1024个字符长的字符串--“Lorem ipsum...”来轻松地耗尽这个容量。问题中的字符串只包含ASCII字符,每个ASCII字符使用4个字节表示,因此1024×4=4096字节。

正如我们所看到的,当我们需要在一个会话cookie中存储附加项时,例如PHP值的序列化元数据,或者当数据包含每个字符消耗超过4个字节的UTF-8字符时,我们很快就开始耗尽空间。为了继续使用cookie存储大于4 KB的会话数据,我们需要编写一个自定义会话驱动程序,该驱动程序为每个响应在多个cookie中划分会话数据,然后在每个请求上重新组合它们。有很好的理由,据我所知,没有现有的包能做到这一点。这就把我带到下一个观点...

我强烈反对使用cookie来存储完整的会话(而不仅仅是会话ID)。这种方法可能暴露安全漏洞,增加请求和响应的开销(包括对同一域上静态资产的请求),存在数据不同步的风险(右键单击应用程序选项卡→重复查看发生了什么),使测试和调试复杂化,并在存储某些类型的数据时导致问题。

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

  1. 将会话数据存储在每个应用程序实例访问的中央服务器上
  2. 在每个站点存储会话状态,并在站点之间复制它
  3. 启动会话后,使用“粘性”会话将用户锚定到一个站点
  4. 编写大量代码来实现自定义会话驱动程序,该驱动程序允许客户端在不使用cookie的情况下传递会话状态,或者实现对cookie进行分区的会话驱动程序

我认为我们可以合理地消除第四种选择。除非我们有很好的理由避免使用前三种方法(对于典型的应用程序,我们通常不使用),否则当前三种选择是标准的、被广泛接受的解决方案时,我们无法证明构建一个跨HTTP来回传输会话数据的系统所需的工作量、复杂性和开销是合理的。

根据问题中的信息,在我看来,你似乎已经理解了其他三个选项背后的概念和含义,所以我不会详细说明每一个选项的解释(但请发表评论,让我知道是否应该这样做)。

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

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

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

read()方法将反向执行这些操作。首先,它将使用包含块数量的cookie的值从请求中的cookie中重新组合每个块,然后,如果我们加密了数据,则可选地解密数据。

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

然后,我们将为会话驱动程序选择一个名称,例如cookie-extended,并在服务提供者的boot()方法中,使用以下方法将其注册为可用的驱动程序:

Session::extend('cookie-extended', ...);

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

最后要注意的是,在数据库中存储会话可能不会像您想象的那样影响性能。在为一个可能不是真正问题的问题投入大量时间进行优化之前,测量这个简单解决方案所产生的实际负载可能是值得的。

 类似资料:
  • 我们正在用Spring云构建一个基于微服务的系统,我们使用Zuul作为边缘服务器和一些后端微服务。在其中一个后端服务中,我们使用Redis来管理,并存储一些与用户相关的对象。 直接访问微服务时一切正常,但通过Zuul访问时出错,因为备份微服务总是获得一个新的ID。我尝试使用和将cookie转发给使用的微服务,但微服务最终没有使用cookie值在Redis中创建spring:sessions。 任何

  • 问题内容: 我正在一个应用程序中工作,该应用程序需要在用户登录期间保留一些数据,但我有一个问题,localStorage,sessionStorage和cookie有什么区别? 我在问我可以使用什么来将某些数据持久化在DOM中,即使用户刷新页面,有人说:使用sessionStorage或localStorage,然后,有人想到了使用ngCookies的想法,因为它可以在每个浏览器,但是,我应该使用

  • 我正在使用Selenium Grid。我最近将VM(node)更新到Windows 10,它不再工作了。以下是详细信息 我通过以下方式将此VM Win10注册为网格节点: (这之前与VM Win8一起工作得很好)我可以在网格上看到这个VM Win10注册了3个浏览器IE11、FF和Chrome 在我的代码中,我通过以下方式创建web驱动程序: 我总是得到这个错误当我执行测试 转发新会话时出错,无法

  • 问题内容: 因此,我正在尝试Selenium自动化,并且试图编写一个测试用例,该用例可以登录,转到特定页面,输入数据,然后按Submit。问题在于,它运行时会键入凭据,然后按“提交”,网站将返回: 该站点使用HTTP cookie来验证授权信息。请启用HTTP cookie以继续。 但是,当我添加此行[以// 1表示]时: 它允许登录通过,直到到达发送消息页面[以// 2表示],然后再次要求提供凭

  • 问题内容: 通过多个实例扩展Web应用程序是Azure云的最大优势之一。为了实现对我们的Web角色云应用程序的多个VM支持,我们正在实现Azure Redis缓存。我们正在使用RedisSessionStateProvider提供程序来维护会话状态。以下是web.config文件中会话管理的配置设置。 我们的问题是会话超时不会随着用户的回发而延长,假设我们的用户在10:00 AM登录到应用程序,那

  • 这就是我想使用WebDriver执行的。 选中“保持用户登录”复选框登录站点 问题是当我关闭驱动程序并重新打开它时,我没有登录。 我的代码看起来像这样-