如何将通过浏览器上传的文件转换为字节?

How to convert uploaded via browser file to bytes?

我需要将图像(File 对象)以字节形式上传到服务器。图片由用户通过输入字段上传到浏览器。

我的问题是图像必须转换为字节,我找不到如何在 JS 中完成。

下面是可以正常工作的 python 代码。

response_with_image = requests.get('some-url.png')
bytes_of_image = response_with_image.content # ->> b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03R\x00\x00\x02\xbc\x08\x02\x00\x00\x00j}\x19\x16\x00\x00\x00\tpHYs\x00\x00\x0fa\x00\x00\x0fa\x01\xa8?\xa7i\x00\x00 \x00IDATx\x9c\xec\xbd\xbf\xcbuKr\x1eZ\xfd\xce\t,s\xb9\xfa\x17\x8ep\xa2@X\xe0\xbf`\x06\'g\xb8\xa9\xfe\x02i\x12#\xb8\xd1\x0c\x0e\'6\x9a\xe4\xfe0JfP$.\xf7"Pdt\x121\x03J\x84\xc0\xd8\xe0\t&\x11:\x18\x8c\x13e\x86\x19\x07:\xbbo\xf0~o\x9fZ\xf5<\xf5tu\xaf\xbd\xdf\xef\xdb3\xabh\x9a\xa7\xaa\xab\xaa{U\xf7\xea\xae\xd3\xeb\xdd\xdfi\xbdw\xbb\xe8\xa2\x8b.\xba\xe8\xa2\x8b.\xba\xe8\xd7\x9d^>\xf6......'

r = requests.put(url_to_upload_file, headers={"Content-Type": "image/png"}, data=bytes_of_image)

目前我可以使用 JS 实现的最佳效果如下 - 代码创建了一个大小不正确(90 KB 而不是 66 KB)且类型正确的文件。当我检查上传的文件时,浏览器无法将其识别为图像,显然是因为我上传的是 base64 而不是字节。

const urlToUploadFile = 'url-provided-by-service'

const imageFile = files[0]
const reader = new FileReader()
reader.onloadend = function () {
    const result = reader.result // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsUAAAQJCAYAAAAuMXXtAAAgAElEQVR4nOzdfWxTd573/f6....

    await axios.put(
        urlToUploadFile,
        { data: result },
        { headers: { 'Content-Type': 'image/png' } }
    ).then(response => {
        console.log('response:', response)
    })

reader.readAsDataURL(imageFile)

我找不到如何将 imageFile 直接转换为 imageFile -> base64 -> 字节的字节。

我认为这是一个 XY 问题,因为您实际上想知道如何将文件直接传递到请求中,而对于如何将 base64 转换为字节的问题,您已经走错了路。所以最好退一步,因为有更直接的解决方案。

我在这里看到两个问题:

  1. 您正在将文件作为数据读取 URL,即使您需要原始格式的文件。我的建议是使用 readAsArrayBuffer instead. But actually you don't have to read or convert the data at all - you could just pass the imageFile directly into axios.put. This should work because File inherits from Blob 并且 axios 接受 Blobs 作为正文。

  2. 您将 { data: result } 而不是 result 作为正文参数传递给 axios.put。结果是 axios 将看到一个带有键 data 和一些值的对象并尝试对其进行编码,但实际上您似乎是在尝试直接上传原始文件(也根据您的 Content-Type)。因此,简单地使用 axios.put(url, theData, { headers: ... }) 而不是 axios.put(url, { data: theData }, { headers: ... }) 应该可以解决它。

顺便说一下,除了硬编码内容类型,您还可以从 imageFile.type.

中获取它

底线是以下代码应该有效:

const urlToUploadFile = 'url-provided-by-service'

const imageFile = files[0]

await axios.put(
    urlToUploadFile,
    imageFile,
    { headers: { 'Content-Type': imageFile.type } }
).then(response => {
    console.log('response:', response)
})