Cookie会话驱动程序不会保存任何验证错误或闪存数据 [英] Cookie session driver won't save any validation error or flash data

查看:51
本文介绍了Cookie会话驱动程序不会保存任何验证错误或闪存数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Laravel中使用cookie会话驱动程序时遇到了困难.

I am having a hard time with the cookie session driver in Laravel.

我有一个简单的表格,上面有一个验证.这是我保存此表单数据的方法:

I have a simple form with a validation in place. This is my method for saving this form data:

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 在视图中以处理下一个请求.

The problem is that, when using the cookie session driver, if I save this form with a description that's 1024 characters long, I'll get redirected back but with no flash data and no $errors in the view for the next request to handle.

示例:

这是使用此行后的POST:

This is a POST after using this line:

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个字节.

In the description field. 1024 bytes to be exact.

相反,如果我只是在字段中填充一些虚拟数据,但没有什么太疯狂了:

Instead, if I just fill the field with some more dummy data but nothing too crazy:

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

If I change the session driver to file:

...有效.

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

But this does not fix my problem. I do need to use the cookie driver for session as the production website is running in 3 different datacenters to achieve high availability. Using the cookie for the session allows the user to hit any of the 3 servers and still continue with it's request without having to use any sticky session or any central session driver.

使用数据库作为驱动程序(也位于具有HA的群集中)不是一个选择,因为这是一个真正的高流量网站,并且会按请求写入 ,而不会听起来很吸引人.我想不惜一切代价防止这种情况.

Using the database as a driver—which is also in a cluster with HA—is not an option as this is a really high traffic website and that would be a write per request which doesn't sound appealing at all. I would like to prevent that at any cost.

有什么可以解决的吗?

我必须说这是网站的后台,但是前端的用户很快就可以在文本区域中写入1024个以上的字符...因此,如果我只是更改后台的驱动程序,则不会帮助,因为我们会遇到同样的问题.

I must say this is the backoffice of the website, but soon the user in the frontend will be able to also write more than 1024 characters in a textarea... so if I just change the driver for the backoffice doesn't help, as we will run into the same for our users.

推荐答案

cookie 会话驱动程序不适用于必须在用户会话中存储大量数据的应用程序.浏览器通常将存储在一个cookie中的数据限制为大约4 KB(4096字节).如我们所见,我们可以通过尝试在会话cookie中存储一个1024个字符长的字符串来轻松耗尽此功能,该问题中的"Lorem ipsum ..." 字符串仅包含ASCII字符,并且每个ASCII字符使用4个字节表示,因此 1024×4 = 4096 个字节.

The cookie session driver is not suitable for applications that must store any significant amount of data in the user's session. Browsers typically limit data stored in one cookie to around 4 KB (4096 bytes). As we found, we can easily exhaust this capacity by attempting to store a 1024-character-long string in the session cookie—the "Lorem ipsum..." string in the question contains only ASCII characters, and each ASCII character is represented using 4 bytes, so 1024 × 4 = 4096 bytes.

我们可以看到,当我们需要在一个会话cookie中存储其他项时(例如PHP值的序列化元数据),或者当数据包含消耗了超过10个字符的UTF-8字符时,我们很快就会开始用尽空间.每个字符4个字节.为了继续使用cookie来存储大于4 KB的会话数据,我们需要编写一个自定义的会话驱动程序,该会话驱动程序将会话数据跨多个cookie划分为每个响应,然后在每个请求上重新组合它们.出于充分的理由,我不知道现有的软件包可以执行此操作.这把我引到了下一点...

As we can see, we quickly begin to run out of space when we need to store additional items in one session cookie, such as the serialization metadata for PHP values, or when the data contains UTF-8 characters that consume more than 4 bytes per character. To continue to use cookies to store session data greater than 4 KB, we'd need to write a custom session driver that partitions session data across multiple cookies for each response and then reassembles them on each request. For good reason, no existing packages do this that I'm aware of. This brings me to my next point...

我要强烈不鼓励使用Cookie来存储完整的会话(而不只是会话ID).这种方法可能会暴露安全漏洞,给请求和响应(包括对同一域中的静态资产的请求)增加开销,存在使数据不同步的风险(右键单击应用程序标签→ Duplicate 以查看发生什么情况),使测试和调试复杂化,并在存储某些类型的数据时引起问题.

I want to strongly discourage the use of cookies for storing a full session (instead of just a session ID). This approach can expose security vulnerabilities, adds overhead to requests and responses (including requests for static assets on the same domain), risks desynchronizing data (right-click app tab → Duplicate to see what happers), complicates tests and debugging, and causes problems when storing certain kinds of data.

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

For the distributed application in the question, we have four options:

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

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

I think we can reasonably eliminate the fourth option. Unless we have a very good reason to avoid using the first three approaches, and for typical applications we usually don't, we cannot justify the amount of work, complexity, and overhead needed to build a system to transfer session data back and forth across HTTP when the first three options are standard, widely-accepted solutions.

根据问题中的信息,在我看来,您已经了解了其他三个选项的概念和含义,因此,我不会详细说明每个选项的解释(但 do 请告诉我是否应该发表评论).

Based on the information in the question, it sounds to me like you already understand the concepts and implications behind the other three options, so I won't elaborate on explanations for each one (but do comment to let me know if I should).

对于没有高级基础架构要求的应用程序,我建议使用第三种方法:粘性会话.这些相对容易设置,并且通常需要在负载均衡器上进行配置,以便一旦客户端启动与应用程序服务器的会话,负载均衡器会将所有后续请求路由到同一服务器,直到会话结束.为了获得高可用性,我们可以将此方法与 Redis会话驱动程序 Redis 服务器配置为在数据中心之间进行主从复制,并且还可以选择

For applications without advanced infrastructure requirements, I recommend the third approach: sticky sessions. These are relatively easy to set up and usually require configuration on the load balancer so that once a client starts a session with an application server, the load balancer routes any subsequent requests to the same server until the session ends. For high-availability, we can combine this approach with the Redis session driver and Redis servers configured for master-slave replication between the datacenters, and, optionally, Redis Sentinel to automate failover. Redis suits session data well and offers better performance than a relational database. If we have multiple application instances at each data center, Redis provides a central location for session data for all instances at one site.

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

For completeness, and to directly answer the question, here's an overview for the development needed to create a cookie-based session driver that handles session data greater than 4 KB. Again, I recommend one of the other approaches described above:

  • First, we'll need to create a new class that implements PHP's SessionHandlerInterface (check out Laravel's cookie session handler for a starting point—we can probably extend this class).

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

The write() method of this class will need to serialize the session $data and then split the data into chunks smaller than 4 KB (for some browsers, less that 4093 bytes). Be sure to account for multibyte characters. Before splitting the data, we may also want to encrypt it if the session contains sensitive information or if we don't want clever users to mess with the values. Then, the method should add a new cookie for each chunk of the session data. Each cookie will need to contain the sequence in its name, and we can add an additional cookie that contains the number of chunks.

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

The read() method will perform these operations in reverse. First, it will reassemble each chunk from the cookies in the request using the value of the cookie that contains the number of chunks, and then, optionally, decrypt the data if we encrypted it.

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

The destroy() method should clear the contents of each cookie that contains a chunk.

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

Then we'll choose a name for the session driver, such as cookie-extended, and, in a service provider's boot() method, register it as an available driver using :

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

我们需要在 config/session.php .env 中指示该应用程序将新驱动程序用于用户会话.

We'll need to instruct the application, in config/session.php or in .env, to use the new driver for user sessions.

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

If you do decide to go down this path, be sure to test the implementation in every browser you plan to support, as different browsers impose their own limitations on the size and quantity of cookies. Even if we've increased the amount of session data we can store as cookies, we're still limited to the maximum number of cookies a browser will accept per domain.

最后一点,将会话存储在数据库中可能不会像您想象的那样对性能产生太大影响.在投入大量时间进行优化以解决可能不是真正问题的问题之前,可能有必要先测量一下这种简单解决方案所产生的实际负载.

As a final note, storing sessions in the database may not impact performance as much as you think. It could be worth measuring the actual load created by this simple solution before investing many hours optimizing for a concern that might not be a real issue.

这篇关于Cookie会话驱动程序不会保存任何验证错误或闪存数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆