我正在使用基于 WebAssembly 的软件,该软件使用需要SharedArrayBuffer
. 它在 Chromium local/deployed 和 Firefox 89 部署中运行良好,但由于最好的性能是在 Firefox 下,我想在我的机器上测试和调整它,所以我运行python -m SimpleHTTPServer
. 在这种情况下,当我在 Firefox 中打开 127.0.0.1:8000 或 0.0.0.0:8000 时,SharedArrayBuffer
是undefined。也许这是一个安全设置,但是当使用 localhost 时,我真的对 Firefox 对这种情况的解释不感兴趣——这应该只是运行。我怎样才能让它工作?我需要不同的网络服务器、不同的设置吗?
2 回答
正如您猜对的那样,它与安全限制有关。已经在 Firefox 79 中实现了有关使用的更改,并将SharedArrayBuffer
很快登陆 Chrome(从 Chrome 92 开始)。(撰写本文时间:2021 年 7 月 13 日。)
主要目的是限制SharedArrayBuffer
s in的使用postMessage
。除非设置了某些限制性 COOP/COEP 标头以防止跨域攻击,否则任何此类尝试都会引发错误:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
不幸的是,没有这些头文件,也就没有全局SharedArrayBuffer
构造函数。显然,这种限制将来可能会取消。虽然对象本身仍然有效(只有通过它们postMessage
才会抛出),但是您需要一种不同的方式来实例化它们。您可以WebAssembly.Memory
改用:
const memory = new WebAssembly.Memory({ initial: 10, maximum: 100, shared: true })
// memory.buffer is instanceof SharedMemoryBuffer
您现在可以更进一步并从中恢复构造函数。因此,使用以下代码作为“shim”,您现有的代码应该可以工作,只要它不尝试通过缓冲区postMessage
:
if (typeof SharedArrayBuffer === 'undefined') {
const dummyMemory = new WebAssembly.Memory({ initial: 0, maximum: 0, shared: true })
globalThis.SharedArrayBuffer = dummyMemory.buffer.constructor
}
// Now, `new SharedArrayBuffer(1024)` works again
进一步阅读:
正如@CherryDT 在评论中指出的那样,问题是缺少本地服务器的标头。网上搜了一下,有一篇博客介绍了在 Firefox 中使用 python 网络服务器开发 WebAssembly 的过程。而不是python -m SimpleHTTPServer
,必须添加一个./wasm-server.py
包含此内容的文件(对于 Python 2):
# Python 2
import SimpleHTTPServer
import SocketServer
class WasmHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
# Python 3.7.5 adds in the WebAssembly Media Type. Version 2.x doesn't
# have this so add it in.
WasmHandler.extensions_map['.wasm'] = 'application/wasm'
if __name__ == '__main__':
PORT = 8080
httpd = SocketServer.TCPServer(("", PORT), WasmHandler)
print("Listening on port {}. Press Ctrl+C to stop.".format(PORT))
httpd.serve_forever()
然后可以在以下位置测试应用程序127.0.0.1:8080