【问题标题】:Laravel Event exceeds Pusher allowed limitLaravel 事件超出 Pusher 允许的限制
【发布时间】:2018-12-11 09:00:20
【问题描述】:

我的 Laravel 应用程序中有一个事件,对于特定记录,它超出了 Pusher 允许的最大限制(10240 字节)。 Laravel 序列化 Event 类上的每个公共属性是否正确?如果是这样,我怀疑序列化模型不应超过 10kb 限制,但无论如何它都会失败。有什么方法可以减小数据内容的大小?

class PostChanged implements ShouldBroadcast
{

 use Dispatchable, InteractsWithSockets, SerializesModels;

 public $post;

 /**
  * Create a new event instance.
  *
  * @return void
  */
  public function __construct(Post $post)
  {
    $this->post = $post;
  }

  /**
  * Get the channels the event should broadcast on.
  *
  * @return \Illuminate\Broadcasting\Channel|array
  */
  public function broadcastOn()
  {
    return new Channel('post-channel.'.$this->post->id);
  }

  public function broadcastWith()
  {
    $extra = [
      'data' => $this->post->data,
    ];

    return array_merge($this->post->toArray(), $extra);
  }
}

产生:

The data content of this event exceeds the allowed maximum (10240 bytes). 
See http://pusher.com/docs/server_api_guide/server_publishing_events for more info

【问题讨论】:

  • $post的内容是什么?另外,你为什么要添加$post->data 两次?它已经包含在$post 变量中。
  • 我发布的代码只是我的代码示例,用于展示我的实现。这不是实际的代码。我的问题是关于$post 对象的序列化与否。

标签: laravel events serialization limit pusher


【解决方案1】:

方法一:在客户端解决

最可靠的方法是 @ExohJosh 所描述的:仅发送事件类型和 ID,以便客户端(很可能是 JavaScript)可以通过单独的 REST(或其他)API 获取更新的记录。

public function broadcastWith()
{
    return [
        'id' => $this->post->id,
    ];
}

方法 2:减少有效负载

另一种(更简单)的方法是只发送客户端所需的数据(你自己想出的那个@sarotnem)。但是,这种方法只有在您确定您提交的属性在任何情况下都不能超过 10KiB 限制的情况下才是安全的。这可以通过输入验证、对数据库列的限制或其他方式来确保。

在选择这种方法时,请务必将可能加载到模型上的任何关系的大小也包括到您的计算中。

定义模型“外部表示”的一种简洁方法是 Laravel 的 API Resources。他们可以让你的代码看起来像这样:

public function broadcastWith()
{
    return [
        'post' => new \App\Http\Resources\PostResource($this->post),
    ];
}

App\Http\Resources\PostResource 可能在哪里:

class PostResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
        ];
    }
}

【讨论】:

    【解决方案2】:

    我过去在处理大对象时采取的一种方法是考虑隔离大对象或传递对象 EG 的引用:id,然后在事件侦听器中执行附加功能。

    在帖子更改的情况下,一种方法可能是:

    帖子已在客户端 1 上更改。

    后端让推送者知道帖子已更改并接收 id

    Pusher 向客户端 2 广播

    客户端 2 正在监听并点击端点以通过 id 获取客户端

    如果这种方法对您不起作用 – 您需要检查您正在序列化的对象是否在数据中有任何冗余,如果您传递的过多则存在问题。

    【讨论】:

    • 但是只传递一个引用不是序列化基本上只传递对象的 id 吗?这就是为什么我认为序列化不会发生,至少不会自动发生。
    • 一般来说,序列化意味着只是转换一个对象进行存储或传输。但是,当 Laravel 作业或事件使用 SerializesModels 特征时,这正是您所描述的。它在事件发射时传递 id,并在执行处理程序时从数据库中恢复模型。但这与您通过 pusher 广播的内容无关。如果您将(反序列化的)对象发送到 pusher,它只会接收它。否则,您的客户必须知道如何通过您的 REST(或其他)API 按 ID 恢复对象。
    • @jsphpl 如果我错了,请纠正我,但是通过使用 SerializesModels 特征,Laravel 不应该只向推送对象的 id 广播吗?相反,如果我 dd()Illuminate\Broadcasting\BroadcastEvent.php@getPayloadFromEvent($event) 中返回完整的对象
    • @sarotnem 没有。当您的工作/事件在队列中时,它“伪序列化”模型(通过传递其 id 并从 db 中恢复它)——这就是 SerializesModels 所做的。在向推送者广播事件时,模型已经恢复。仅当作业在队列中时,模型才处于这种“序列化到类+id”状态。在处理作业/事件的那一刻,laravel 将从数据库中恢复模型。
    【解决方案3】:

    经过大量试验,我设法通过简单地取消设置$post->toArray() 生成的数组的一些不必要的值来使其工作。

    我还注意到broadcastWith() 方法将有效负载作为数组返回,而不是序列化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-09
      • 1970-01-01
      • 2018-01-23
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      相关资源
      最近更新 更多