如何在Scala.js中将ByteBuffer转换为BodyInit?

How to convert ByteBuffer to BodyInit in Scala.js?

我想在 Scala.js 中使用 sendBeacon API 并以 ByteBuffer 的形式发送二进制数据,但我无法将其转换为 BodyInit.我正在使用 boopickle 生成包含我实例的编码数据的二进制文件 ByteBuffer

按照建议,我尝试将 ByteBuffer 转换为 ArrayBuffer 并将其转换为 BodyInit。但是,当 运行 此代码在 Firefox 53.0.3 上时,我没有收到运行时错误,而是有效负载仅包含 [object ArrayBuffer] 而不是二进制数据本身。

代码如下:

import scala.scalajs.js.typedarray.TypedArrayBufferOps._
import boopickle.Default._
import org.scalajs.dom.experimental.BodyInit
import org.scalajs.dom.experimental.beacon._   

case class Message(firstName: String, lastName: String)
val message = Message("John", "Doe")
val data = Pickle.intoBytes(message).arrayBuffer()
dom.window.navigator.sendBeacon("/api", data.asInstanceOf[BodyInit])

在 Scala.js 中,直接字节缓冲区由 TypedArrays 支持。

因此,当您分配 ByteBuffer 时,请确保它是直接的:

val buf = ByteBuffer.allocateDirect(1024)

然后,您可以使用 TypedArrayBufferOps 访问底层 TypedArray:

import scala.scalajs.js.typedarray.TypedArrayBufferOps._
sendBeacon("http://foo.bar/", buf.typedArray)

tl;dr 改为这样做:

val data = Pickle.intoBytes(message).typedArray()
dom.window.navigator.sendBeacon("/api", data.asInstanceOf[BodyInit])

您应该使用 typedArray() 而不是 arrayBuffer(),因为 ArrayBuffer 是一个更底层的结构,不被 sendBeacon in Mozilla (it accepts an ArrayBufferView) 接受。

还要注意 ByteBuffer 上的 arrayBuffer() 通常是没有意义的,因为 ByteBuffer 可能只代表底层缓冲区的一部分。您还需要使用 arrayBufferOffset()