通过 Flask 将 numpy 数组作为字节从 python 发送到 JS
Send numpy array as bytes from python to JS through Flask
一个numpy数组应该从python通过flask发送到JS。我不想对其进行 jsonify 化并发送,因为它会增加响应的大小并最终增加响应时间。所以我想我可以使用 tobytes() 将 numpy 转换为字节,通过 flask 将字节发送到 JS,然后将字节转换回 JS 中的浮点数,发现 答案很有帮助。
操作列表是
byte_arr = np.array([5.6], dtype=np.float32).tobytes() # Used one value just to make it simple
return byte_arr # Bytes can be directly sent from flask as response
在 JS 中,
str = response.text
bytes = Uint8Array.from(str, c => c.charCodeAt(0))
floats = new Float32Array(bytes.buffer)
但是在 JS 中转换为 float 时,我没有得到正确的值。在调试时我发现在 JS 中,Uint8 数组中的某些值与从 python 发送的字节值不匹配。
JS: console.log(bytes) // [51, 51, 255, 64]
Python: for val in byte_arr: print(val, end=" ") // 51, 51, 179, 64
为了验证,我在 python 中创建了另一个客户端,发出相同的请求并将响应字节转换为浮点数。我在这里也遇到了同样的问题。所以我缩小了问题出在服务器端而不是客户端的范围。我在使用多个值时发现的另一件有趣的事情是,只有大于 127(我猜是)的数字才会转换为 255。
在尝试一些随机的 hack 时,我尝试在发送响应之前使用 python 的 chr() 方法将字节整数转换为字符,并且在客户端进行了转换。
byte_arr = np.array([5.6], dtype=np.float32).tobytes()
byte_arr_char = "".join([chr(i) for i in byte_arr])
return byte_arr_char
但我的问题是,这是一个理想的解决方案,还是我在这里做一些 hack 以使其工作?谁能帮我理解为什么发送没有 chr() 的纯字节不起作用?
如果你没有明确设置MIME type,我想Flask会把它当作文本数据。您的浏览器似乎已经用 ASCII 解码了二进制数据,这可以解释为什么只有大于 127 的值才会受到影响。
因此,请尝试在 Flask 中设置响应的Content-Type
:
@app.route('/your/url/to/numpy/data')
def get_nparray():
your_np_array = np.array([5.6], dtype=np.float32)
response = flask.make_response(your_np_array.tobytes())
response.headers.set('Content-Type', 'application/octet-stream')
# response.headers.set('Content-Disposition', 'attachment', filename='np-array.bin')
return response
或者,有一个辅助函数 flask.send_file
可以在一行中构建响应。请找一个例子 here.
除此错误外,还要注意endianness of your binary data, which is hardware specific. I would refer you to this answer (Javascript Typed Arrays and Endianness).
一个numpy数组应该从python通过flask发送到JS。我不想对其进行 jsonify 化并发送,因为它会增加响应的大小并最终增加响应时间。所以我想我可以使用 tobytes() 将 numpy 转换为字节,通过 flask 将字节发送到 JS,然后将字节转换回 JS 中的浮点数,发现
操作列表是
byte_arr = np.array([5.6], dtype=np.float32).tobytes() # Used one value just to make it simple
return byte_arr # Bytes can be directly sent from flask as response
在 JS 中,
str = response.text
bytes = Uint8Array.from(str, c => c.charCodeAt(0))
floats = new Float32Array(bytes.buffer)
但是在 JS 中转换为 float 时,我没有得到正确的值。在调试时我发现在 JS 中,Uint8 数组中的某些值与从 python 发送的字节值不匹配。
JS: console.log(bytes) // [51, 51, 255, 64]
Python: for val in byte_arr: print(val, end=" ") // 51, 51, 179, 64
为了验证,我在 python 中创建了另一个客户端,发出相同的请求并将响应字节转换为浮点数。我在这里也遇到了同样的问题。所以我缩小了问题出在服务器端而不是客户端的范围。我在使用多个值时发现的另一件有趣的事情是,只有大于 127(我猜是)的数字才会转换为 255。
在尝试一些随机的 hack 时,我尝试在发送响应之前使用 python 的 chr() 方法将字节整数转换为字符,并且在客户端进行了转换。
byte_arr = np.array([5.6], dtype=np.float32).tobytes()
byte_arr_char = "".join([chr(i) for i in byte_arr])
return byte_arr_char
但我的问题是,这是一个理想的解决方案,还是我在这里做一些 hack 以使其工作?谁能帮我理解为什么发送没有 chr() 的纯字节不起作用?
如果你没有明确设置MIME type,我想Flask会把它当作文本数据。您的浏览器似乎已经用 ASCII 解码了二进制数据,这可以解释为什么只有大于 127 的值才会受到影响。
因此,请尝试在 Flask 中设置响应的Content-Type
:
@app.route('/your/url/to/numpy/data')
def get_nparray():
your_np_array = np.array([5.6], dtype=np.float32)
response = flask.make_response(your_np_array.tobytes())
response.headers.set('Content-Type', 'application/octet-stream')
# response.headers.set('Content-Disposition', 'attachment', filename='np-array.bin')
return response
或者,有一个辅助函数 flask.send_file
可以在一行中构建响应。请找一个例子 here.
除此错误外,还要注意endianness of your binary data, which is hardware specific. I would refer you to this answer (Javascript Typed Arrays and Endianness).