用于加载大型数据集的 Rails 和服务器发送事件 (SSE)

问题描述 投票:0回答:0

我的地图应用程序需要从服务器加载大量 JSON 数据以呈现初始地图视图。一个地图有很多区域,一个区域看起来像下面这样。数据字段存储 gzip 压缩的 JSON 数据。一个大地图可以有 50 个区域,每个区域压缩后大约 2MB。

create_table "regions", force: :cascade do |t|
  t.integer "map_id", null: false
  t.binary "data", null: false
  t.index ["map_id"], name: "index_regions_on_map_id"
end

我有一个控制器,它流式传输地图的所有区域:

class MapController < ApplicationController
  include ActionController::Live

  def stream_regions
    response.headers['Content-Type'] = 'text/event-stream'
    response.headers['Last-Modified'] = Time.now.httpdate
    sse = SSE.new(response.stream, retry: 300, event: 'open')
    index = 0
    @map.regions.each do |region|
      sse.write(
        id: index += 1, 
        event: 'message',
        { done: false, region: Base64.encode64(region.data) }
      )
    end
    sse.write(id: index += 1, event: 'message', { done: true })
  rescue ActionController::Live::ClientDisconnected
    sse.close
  ensure
    sse.close
  end
end

在客户端,我有这样的东西:

const streamRegions = async (mapId: string): Promise<string[]> => {
  return new Promise((resolve) => {
    const source = new EventSource(
      `/maps/${mapId}/stream_regions`
    );

    const regions: string[] = [];
    source.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (data.done) {
        source.close();
        resolve(regions);
      } else {
        const bytes = Buffer.from(data.region, "base64");
        const json_string = pako.inflate(bytes, { to: "string" });
        const json = JSON.parse(json_string);
        regions.push(json);
      }
    };
  });
};

虽然这很有效而且速度很快(加载大地图需要 3 秒),但有几件事让我觉得很奇怪:

  1. SSE 代表服务器发送的事件。我的区域对象绝对不是事件,它们是 gzipped JSON 数据的大量有效载荷。

  2. SSE 不支持二进制数据。所以在服务器端,我必须先将二进制数据转换为 base64 字符串,然后再使用 SSE 传输它们。然后在客户端,我不得不再次将反向对话恢复为二进制。对于大地图,这似乎只增加了 100-200 毫秒的额外处理时间。然而,它也将通过网络传输的数据大小扩大了大约 30%,因此并不理想。

  3. 再次因为 SSE 不支持二进制数据,我不得不使用 pako.inflate 在客户端手动处理数据膨胀(解压缩)

所以我的问题是:我想念在这里使用 SSE 吗?使用 Rails 有更好的方法吗?基本上,我想尽量减少用户在等待地图加载时看到微调器的时间。在下载所有区域之前,无法显示地图。

ruby-on-rails server-sent-events
© www.soinside.com 2019 - 2024. All rights reserved.