【问题标题】:Ajax.post --> dom.fetchAjax.post --> dom.fetch
【发布时间】:2022-01-19 14:41:20
【问题描述】:

我正在尝试使用 dom.fetch(或 dom.Fetch.fetch)api 而不是 Ajax.post,但遇到了一些问题:

这是从 ajax 到 fetch 的正确翻译吗?

Ajax.post(
  url = "http://localhost:8080/ajax/myMethod",
  data = byteBuffer2typedArray(Pickle.intoBytes(req.payload)),
  responseType = "arraybuffer",
  headers = Map("Content-Type" -> "application/octet-stream"),
)

dom.fetch(
  "http://localhost:8080/fetch/myMethod",
  new RequestInit {
    method = HttpMethod.POST
    body = byteBuffer2typedArray(Pickle.intoBytes(req.payload))
    headers = new Headers {
      js.Array(
        js.Array("Content-Type", "application/octet-stream")
      )
    }
  }
)

虽然在 js 端抛出“ReferenceError: fetch is not defined”,但如果替换为dom.Fetch.fetch,则相同。

我的设置:

新鲜的 jsdom 19.0.0 与

npm init private
npm install jsdom

项目/plugins.sbt

libraryDependencies += "org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.1.0"
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0")

build.sbt(在 js 项目中)

libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.0.0"
jsEnv := new JSDOMNodeJSEnv(JSDOMNodeJSEnv.Config()
  .withArgs(List("--dns-result-order=ipv4first")))

认为 Scala.js 1.8 不需要 jsEnv 解决方法(请参阅 https://github.com/scala-js/scala-js-js-envs/issues/12#issuecomment-958925883)。但是当我运行 ajax 版本时仍然需要它。通过解决方法,我的 ajax 版本可以正常工作,因此我的节点安装似乎很好。

【问题讨论】:

    标签: ajax fetch scala.js


    【解决方案1】:

    fetch API 默认仅在浏览器环境中可用,在 Node.js 中不可用。 node-fetch 也不会被jsdom 拉入(或至少不会重新导出),因此fetch 在当前的包/环境设置中不可用。

    可能的解决方案:

    1. 将 ScalaJS 设置为朝上,使其在 NodeJS 上调用 node-fetch,在浏览器上调用 fetch
    2. 使用在两个平台上都可用的 XMLHttpRequest

    (请参阅 Scala Discord 的 #scala-js 频道中的 here,了解为什么这个答案很短。TL;DR,Marc 要求我在这里回答,以便我可以收到代表赏金以帮助不和谐。上下文的screenshot 可用。)

    【讨论】:

    • fwiw 指向特定 Discord 频道的链接经不起时间的考验。如果您在答案中包含相关部分,那么多年后的人们仍然可以从这些信息中受益:)
    • 听起来不错,我会附上截图。
    • 太好了,谢谢@Aly!
    • 嗨@Aly - 认为我们在这里交流比在 Discord 上更好。我认为没有任何理由删除您的答案。只是想看看是否有可能,还是我错过了其他原因?
    • 我只是没想到我的答案有更有用的信息集。至少如果你不想删除它,我认为它不应该被标记为正确答案?
    【解决方案2】:

    @Aly here 和 @armanbilge here 在 Discord 上的 scala-js 频道上获得了帮助,他们指出:

    • fetch 默认在 Node.js 或 JSDOM 中不可用,仅在浏览器中可用。
    • scala-js-dom 提供对浏览器 API 的类型安全访问,而不是 Node.js API。

    浏览器 API 和 Node API 之间的区别我之前并不清楚,尽管在 scala-js tutorial 的第 6 步中有很好的描述。

    因此,scala-js-dom API 的dom.fetch 在浏览器中运行 js 程序时有效,但在运行使用 Node jsEnv(ironment) 的测试时无效!要在测试中获取,必须npm install node-fetch 并使用node-fetch,也许通过使用 scala-js 制作外观。

    因为我希望我的代码同时适用于浏览器 (scala-js-dom) 和测试 (Node.js),所以我最终退回到简单地使用带有 XMLHttpRequest 的 Ajax.post 实现:

    case class PostException(xhr: dom.XMLHttpRequest) extends Exception {
      def isTimeout: Boolean = xhr.status == 0 && xhr.readyState == 4
    }
    
    val url         = s"http://$interface:$port/ajax/" + slothReq.path.mkString("/")
    val byteBuffer  = Pickle.intoBytes(slothReq.payload)
    val requestData = byteBuffer.typedArray().subarray(byteBuffer.position, byteBuffer.limit)
    val req         = new dom.XMLHttpRequest()
    val promise     = Promise[dom.XMLHttpRequest]()
    
    req.onreadystatechange = { (e: dom.Event) =>
      if (req.readyState == 4) {
        if ((req.status >= 200 && req.status < 300) || req.status == 304)
          promise.success(req)
        else
          promise.failure(PostException(req))
      }
    }
    req.open("POST", url) // (I only need to POST)
    req.responseType = "arraybuffer"
    req.timeout = 0
    req.withCredentials = false
    req.setRequestHeader("Content-Type", "application/octet-stream")
    req.send(requestData)
    
    promise.future.recover {
      case PostException(xhr) =>
        val msg    = xhr.status match {
          case 0 => "Ajax call failed: server not responding."
          case n => s"Ajax call failed: XMLHttpRequest.status = $n."
        }
        println(msg)
        xhr
    }.flatMap { req =>
      val raw       = req.response.asInstanceOf[ArrayBuffer]
      val dataBytes = TypedArrayBuffer.wrap(raw.slice(1))
      Future.successful(dataBytes)
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-10
      • 2013-01-11
      • 2020-03-22
      • 2016-02-28
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      相关资源
      最近更新 更多