Laravel事件超出Pusher允许的限制。

7

我的Laravel应用程序中有一个事件,对于特定的记录,它超出了Pusher允许的最大限制(10240字节)。 Laravel是否会序列化事件类上的每个公共属性? 如果是这样,我怀疑序列化模型不应该超过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 变量中了。 - Jerodev
我发布的代码只是我的实现示例,不是真正的代码。我的问题是关于$post对象是否需要序列化的。 - sarotnem
3个回答

9

方法1:在客户端解决问题

最可靠的方法是像@ExohJosh所描述的那样:仅发送事件类型以及ID,因此客户端(很可能是JavaScript)可以通过单独的REST API获取更新后的记录。

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

方法2:减少有效载荷

另一种(更简单)的方法是仅发送客户端所需的数据(@sarotnem您自己找出了这个方法)。但是,如果您肯定知道提交的属性绝对不会超过10KiB限制,则此方法才是安全的。可以通过输入验证、DB列的限制或其他手段来确保这一点。

选择此方法时,请务必将可能加载到模型上的任何关系的大小计入计算。

定义模型“外部表示”的一种简洁方式是 Laravel 的 API 资源。它们可以让您的代码看起来像这样:

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,
        ];
    }
}

1
过去我在处理大对象时采用的方法是考虑将大对象分离或传递对象的引用,例如id,然后在事件监听器中执行附加功能。
在帖子发生更改的情况下,一种方法是:
客户端1上更改帖子。
后端让pusher知道帖子已更改并接收id
Pusher广播到客户端2
客户端2正在侦听并击中端点以通过id获取客户端
如果这种方法对您不起作用-您需要检查您正在序列化的对象是否具有任何数据冗余,如果传递了太多,则存在问题。

但是仅传递引用并不是序列化基本上通过仅传递对象的ID来完成的操作吗?这就是为什么我认为序列化不会自动发生的原因。 - sarotnem
通常序列化就是将一个对象转换为可存储或可传输的形式。然而,当 Laravel Job 或 Event 使用 SerializesModels 特质时,它恰好做了你描述的事情。它在事件发出时传递 id,在处理程序执行时从数据库中还原模型。但这与你通过 pusher 广播的内容无关。如果您将(反序列化的)对象发送到 pusher,则它只需要接受即可。否则,您的客户端必须知道如何通过 ID 通过 REST(或其他方式)API 还原该对象。 - jsphpl
@jsphpl 如果我理解有误,请纠正我,使用SerializesModels特性,Laravel是否应该只向Pusher广播对象的ID?但是,如果我在Illuminate\Broadcasting\BroadcastEvent.php@getPayloadFromEvent($event)中使用dd(),则会返回完整的对象。 - sarotnem
1
@sarotnem 不是的。它通过传递模型的ID并从数据库中恢复来“伪序列化”模型,而您的作业/事件在队列中 - 这就是SerializesModels所做的事情。在将事件广播到推送程序时,模型已经被恢复。该模型仅在作业在队列中时处于“序列化为类+ ID”的状态。在处理作业/事件时,Laravel会从数据库中恢复模型。 - jsphpl

0

经过相当多的尝试,我成功地通过简单地取消 $post->toArray() 产生的数组的一些不必要的值来使其工作。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接