为什么在FileSystemFileHandle上postMessage失败?

huangapple go评论68阅读模式
英文:

Why postMessage fails on FileSystemFileHandle?

问题

我有index.html

const openButton = document.querySelector('#open'),
  pickerOpts = {
    types: [{
      accept: {
        "text/*": [".txt"],
      },
    }, ],
    excludeAcceptAllOption: true,
    multiple: false,
  }

openButton.addEventListener('click', async() => {
  const handle = await window.showOpenFilePicker(pickerOpts),
    obj = {
      a: 'a'
    },
    tab = window.open('tab.html')
  setTimeout(() => {
    // not work, the tab.html receives nothing
    tab.postMessage(handle, '*')
    // works fine
    // tab.postMessage(obj, '*')
  }, 1000)
})

tab.html

window.addEventListener('message', (e) => {
  console.log(e.data)
})

postMessage 对于通用的 JavaScript 对象可以正常工作,但无法发送 FileSystemFileHandle。我该如何修复这个问题?

结构化克隆算法 - Web API | MDN 指出 FileSystemFileHandle 应该是支持的。

英文:

I have index.html:

<!-- language: lang-js -->

const openButton = document.querySelector(&#39;#open&#39;),
  pickerOpts = {
    types: [{
      accept: {
        &quot;text/*&quot;: [&quot;.txt&quot;],
      },
    }, ],
    excludeAcceptAllOption: true,
    multiple: false,
  }

openButton.addEventListener(&#39;click&#39;, async() =&gt; {
  const handle = await window.showOpenFilePicker(pickerOpts),
    obj = {
      a: &#39;a&#39;
    },
    tab = window.open(&#39;tab.html&#39;)
  setTimeout(() =&gt; {
    // not work, the tab.html receives nothing
    tab.postMessage(handle, &#39;*&#39;)
    // works fine
    // tab.postMessage(obj, &#39;*&#39;)
  }, 1000)
})

<!-- language: lang-html -->

&lt;button id=&quot;open&quot;&gt;open&lt;/button&gt;

<!-- end snippet -->

and tab.html:

<!-- language: lang-js -->

window.addEventListener(&#39;message&#39;, (e) =&gt; {
  console.log(e.data)
})

<!-- end snippet -->

The postMessage works fine for general JavaScript objects but fails to send a FileSystemFileHandle. How should I fix this?

The structured clone algorithm - Web APIs | MDN indicates that FileSystemFileHandle should be supported.

答案1

得分: 1

FileSystemFileHandle 对象确实可以通过 postMessage() 使用的结构化克隆算法进行克隆,但是如果您的两个文档不在相同的源上,当接收端尝试反序列化对象时,此操作应该会引发 DataCloneError 异常。

请注意,file:// 系统上的两个文档将被视为跨源。

要处理这种错误,您应该能够在接收端添加一个 messageerror 事件,但这仅在Firefox中适用(在使用 navigator.storage.getDirectory() 时),在Chrome中不适用。
在该浏览器中,除了 data 将为 null 这一事实之外,没有其他信息表明操作失败。但这违反了规范,因此可能被视为错误。

但无论如何,如果您无法访问要发布的窗口,您可以知道它会引发异常,因此这只会对您有一点帮助。
相反,您可能需要设置一个代理API,在这个API中,您的主页面将请求文件系统,然后通过调用 postMessage 让弹出窗口导航到它。我建议您为此目的设置一个唯一的 MessageChannel,以便您可以将通信封装成 Promise。

然而,重新编写整个API不是一个小项目,因此您可能只需从您确定会使用的少数几种方法开始。

英文:

FileSystemFileHandle objects can indeed be cloned through the structured cloning algorithm used by postMessage(), however, if your two documents are not on the same origin, this operation should throw a DataCloneError exception on the receiving end when it will try to deserialize the object.

Note that two documents on the file:// system will be seen as cross-origin.

To handle such an error, you should be able to add a messageerror event on the receiving end, however this is the case only in Firefox (when using navigator.storage.getDirectory()), but not in Chrome.
In that browser, there is thus nothing that tells us that it failed, apart from the fact that data will be null. But this is against the specs, so may be considered a bug.

But anyway, you can know that it will throw if you can't access the window you're posting to, so that would help you only a little.
Instead, what you will probably have to do is to set up a proxy API where your main page will request the FileSystem, and then let the popup navigate it through calls to postMessage. My advice would be to set up a unique MessageChannel to this effect, so that you can promisify the communication.

However rewriting the whole API is not a small project, so you may to instead start only with the few methods you're sure you'll be using.

huangapple
  • 本文由 发表于 2023年8月4日 05:36:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76831740.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定