将 Any/Blob 显式转换为 ArrayBuffer 仍然会给我一个无法处理的 Blob

Explicitly casting Any/Blob to ArrayBuffer still gives me a Blob I can't process

在我的 websocket 上,我期望从服务器到客户端的二进制消息(另一种方式有效)。我想将其转换为 Array[Byte] 以将其进一步处理为 protobuf-message

ws.onmessage = {
  (event: MessageEvent) =>
    val msg = event.data.toString
    dom.window.console.log(msg) 

    val x = event.data.asInstanceOf[ArrayBuffer]
    val df = new DataView(x)
    dom.window.console.log("result")
    dom.window.console.log(bin2User(df).toString)
}

private def bin2User(data: DataView): User = {
    val bytes = new Array[Byte](data.byteLength)

    for(index <- 0 to data.byteLength) {
      bytes(index) = data.getInt8(index)
    }

    User.parseFrom(bytes)
  }

现在dom.window.console.log(msg) 给我

[object Blob]

Blob { size: 9, type: "" }

我希望 xArrayBuffer 类型,因为 explicit 强制转换,但遗憾的是,它不是,因为我得到

TypeError: DataView: expected ArrayBuffer, got Blob

我该如何克服这个问题?

我试过:

val fr = new FileReader
fr.readAsArrayBuffer(event.data.asInstanceOf[Blob])
val y = fr.result.asInstanceOf[ArrayBuffer]
dom.window.console.log(y)

但这会为 y

打印 null

TypeError: y is not an object

您快到了:FileReader 是异步的,因此您必须:

val fr = new FileReader
fr.onload = { _ =>
  val y = fr.result
  dom.window.console.log(y)
}

fr.readAsArrayBuffer(event.data.asInstanceOf[Blob])

这基本上是来自 this response 的翻译示例。

你以后可能想把它包装起来API:

import scala.concurrent.Promise

def blob2ArrayBuffer(blob: Blob): Future[ArrayBuffer] = {
  val result = Promise[ArrayBuffer]()
  val fr = new FileReader
  fr.onload = { _ => result.success(fr.result) }
  fr.readAsArrayBuffer(blob)
  result.future
}

正如一些人已经指出的那样,设置 ws.binaryType = "arraybuffer" 也足够了。

这样做:

 ws.onmessage =
      {
        ws.binaryType = "arraybuffer"

        (event: MessageEvent) => 

            val msg = event.data.asInstanceOf[ArrayBuffer]
            dom.window.console.log(msg)

结果

ArrayBuffer { byteLength: 9 }