文件上传

lxf2023-03-16 11:50:01

在上述文章中,提到了 API 接口可以通过几种 Content-Type 进行传递。

如何传递一张图片呢?

既然 Content-Type 可以选择 Request Body 的 MIME Type,那么直接指定 Content-Type: image/jpeg 应该就可以传递 JPEG 图片。

那如何设置 Content-Type: image/jpeg 所对应的 Request Body?

本篇文章仅以 Javascript 浏览器端作为示例,Python/Java 虽然 API 不同,但是原理是一样的

在 Javascript 中,可使用 TypedArray 表示二进制。而 JPEG 资源作为二进制资源可使用 TypedArray 表示。

如此,在 fetch API 中将 body 配置TypedArray 即可传递 image/jpeg 图片。

await fetch('/upload-jpeg', {
  body: new Uint8Array([0xFF, 0xD8, 0xFF, 0xDB]),
  headers: {
    'content-type': 'image/jpeg'
  }
})

那如何将上传的 image/jpeg 图片读作 TypedArray 呢?

上传效果可在 Apifox 查看:

文件上传

上传文件

<input type="file" id="input" accept="image/jpeg" onchange="handleFiles(this.files)">

在浏览器中,通过 input[type=file] 来点击上传文件,此时监听 onChange 事件,可以获取到 File 对象,其中从中可以读取文件内容。详见文档 file input。

可通过 accept 属性限制可接受的 MIME 文件类型。

而读取文件内容,需要转化 File/BlobTypedArray,一般使用 FileReader API

Blob API

Blob API 用以在浏览器中模拟文件资源,在第二个参数中可指定 MIME Type

// 模拟 HTML 资源
const html = [`<h1>hi, shanyue</h1>`]
const htmlBlob = new Blob(html, { type : 'text/html' })

// 模拟 WEBP 资源
const webp = [
  new Uint8Array([82,73,70,70,158,6,0,0,87,69,66,80,86,80,56,32,146,6,0,0,112,58,0,157,1,42,232,3,126,0,62,145,72,162,76,165,164,35,34,33,114,72,112,176,18,9,105,110,225,119,97,27,243,153,105,23,229,124,61,240,131,229,95,100,121,106,196,167,228,191,107,127,75,195,254,211,95,231,247,215,64,22,115,111,36,255,201,249,20,124,195,202,63,161,38,155,95,131,255,79,250,246,15,238,156,127,243,245,174,164,41,37,31,231,255,63,90,234,66,146,81,254,127,243,245,174,164,41,37,31,231,255,63,90,234,66,146,81,254,127,243,245,174,164,41,37,31,231,255,63,90,234,66,146,81,254,127,243,245,153,194,96,66,2,207,70,42,56,156,171,214,186,144,164,148,127,159,252,253,107,169,10,73,71,249,255,207,214,186,144,164,148,127,149,88,107,227,172,5,76,238,201,99,240,65,88,82,198,59,70,208,197,129,139,0,200,52,61,135,199,151,184,2,7,32,106,208,201,107,7,79,250,192,190,171,176,84,140,149,254,230,3,168,225,44,135,6,90,71,131,166,5,155,164,59,234,210,159,148,252,180,123,88,181,255,63,249,250,215,82,20,146,143,243,255,159,173,117,33,73,40,255,63,249,245,27,196,75,165,134,81,141,26,114,117,156,64,35,221,192,222,115,98,6,199,9,162,100,173,149,61,246,16,55,26,161,185,105,58,59,64,255,118,78,65,104,232,229,154,69,156,25,138,191,185,241,130,192,232,206,85,42,135,6,194,218,22,200,130,92,202,152,124,31,50,30,160,148,127,159,252,253,107,169,10,73,71,249,255,207,214,186,144,164,148,127,159,251,114,45,56,176,156,15,52,101,140,238,230,96,78,116,209,162,92,145,160,71,211,58,158,25,29,59,103,7,116,65,199,91,136,94,239,133,249,74,69,85,235,93,72,82,74,63,207,254,126,181,212,133,36,163,252,255,231,235,93,72,131,99,84,175,125,11,186,175,90,234,66,146,81,254,127,243,245,174,164,41,37,31,231,255,63,90,234,66,146,81,254,127,243,245,174,164,41,37,31,231,255,63,90,234,66,146,81,254,127,243,245,174,164,41,37,31,229,0,0,254,255,222,180,0,0,1,42,121,231,232,188,49,206,247,127,241,56,21,207,127,146,39,117,223,250,152,248,217,81,25,50,166,135,185,137,247,62,185,121,106,41,202,95,94,255,243,97,51,156,253,88,5,217,202,222,92,128,117,253,170,194,127,207,92,173,77,74,234,88,47,63,182,191,214,151,105,176,236,245,250,185,126,50,6,95,23,71,93,89,252,112,48,165,79,241,201,190,109,144,172,225,126,83,161,34,131,155,101,121,119,117,175,62,229,214,19,230,251,73,13,2,220,94,41,235,161,100,25,0,84,107,165,217,154,61,172,127,191,135,62,134,242,82,60,205,182,192,201,48,166,205,157,47,49,50,27,76,186,15,131,135,97,173,4,124,13,120,235,249,170,226,48,199,164,95,183,223,161,96,101,247,191,76,49,130,234,160,88,100,143,40,34,2,61,137,207,131,75,132,175,88,215,46,88,169,35,106,156,238,220,226,29,240,168,69,14,134,65,215,240,34,234,245,18,90,244,128,108,69,30,143,86,29,98,39,51,52,65,126,97,8,184,53,248,120,136,237,66,129,43,152,68,118,6,139,127,135,146,247,48,168,211,144,52,246,192,210,174,41,203,97,253,206,107,73,219,213,126,229,35,226,228,48,137,97,230,159,200,14,161,193,2,136,47,133,212,44,120,72,119,46,65,106,96,208,26,221,247,132,133,217,163,187,118,161,175,204,118,74,157,120,66,141,204,205,182,196,11,11,165,141,67,208,26,194,23,93,206,48,84,91,91,188,188,127,32,161,123,208,135,128,41,91,239,104,177,166,79,177,177,26,107,36,222,54,91,120,122,146,90,236,197,72,26,243,222,223,102,45,104,126,86,148,31,179,217,157,132,14,214,231,164,75,193,198,123,107,179,75,163,255,240,132,177,27,44,189,70,10,98,180,95,31,95,178,124,41,51,247,32,145,155,104,209,80,185,202,8,13,87,9,7,251,225,33,144,62,175,158,216,49,243,235,47,57,29,251,194,158,98,187,195,116,134,56,208,34,83,226,160,34,149,202,230,136,96,3,211,209,74,231,151,89,42,109,247,48,209,31,182,242,155,119,208,47,157,254,28,231,35,55,164,251,61,38,249,170,164,112,134,49,40,199,29,218,189,217,89,229,127,174,48,186,51,110,12,189,35,6,45,229,187,92,238,62,34,199,6,57,194,235,31,202,54,45,177,54,143,36,111,31,90,46,235,96,144,18,56,181,52,177,39,190,98,94,141,23,42,239,244,209,180,204,191,6,49,172,167,98,119,240,239,56,33,43,218,58,207,151,223,122,139,47,24,122,66,195,156,91,33,130,116,60,76,160,114,244,100,203,223,228,165,49,15,192,81,113,191,35,24,196,96,44,211,203,152,138,150,10,161,38,215,212,142,197,197,97,143,89,226,144,18,83,230,128,59,14,138,10,100,116,171,119,175,238,64,191,164,151,142,203,18,121,149,79,218,108,195,63,103,30,27,92,190,1,74,140,231,238,224,241,107,68,137,125,159,179,63,242,241,116,121,225,87,187,110,83,222,158,228,121,28,147,193,150,129,170,88,61,61,80,197,232,246,134,54,43,40,68,123,160,225,24,181,224,36,237,72,174,43,90,37,116,208,242,22,170,65,178,99,122,170,167,165,19,210,6,4,207,86,157,131,34,246,95,8,21,207,225,201,151,47,161,110,199,150,61,229,180,211,193,104,130,198,172,44,27,91,252,140,57,103,196,40,152,219,159,28,117,225,245,130,150,37,190,112,245,10,125,228,247,132,21,220,223,170,50,140,209,239,99,12,78,139,125,97,26,237,188,98,223,237,65,164,139,205,98,116,166,208,196,78,197,201,234,69,23,205,160,113,164,103,121,85,136,85,235,192,27,213,87,57,110,1,8,50,208,104,208,85,180,168,172,77,174,32,160,89,27,179,249,169,105,219,220,221,67,13,245,67,247,169,81,147,10,91,70,230,126,25,26,251,210,111,130,27,83,235,215,240,68,176,246,251,95,136,70,21,78,13,183,109,241,150,104,214,22,45,46,124,139,32,31,210,29,192,122,134,27,112,21,164,85,188,131,6,49,111,43,66,0,21,21,197,95,132,141,220,249,170,17,117,34,119,90,232,53,190,167,59,198,223,92,113,22,156,53,190,117,207,103,77,192,22,151,1,75,97,255,48,185,30,215,142,239,191,247,174,103,143,12,135,199,13,35,88,213,193,251,234,82,99,39,120,179,77,252,57,167,89,186,116,162,223,166,14,203,114,122,191,205,49,2,248,230,224,228,248,82,249,131,161,59,231,180,134,2,250,137,104,247,55,91,24,232,95,121,52,195,171,52,169,54,53,98,32,64,120,38,42,176,214,2,184,22,17,13,120,102,254,224,239,170,131,64,172,171,200,242,57,89,166,183,165,159,79,78,52,77,7,255,242,20,206,65,16,231,226,97,42,67,34,166,48,78,64,205,120,148,117,47,212,202,227,112,0,4,48,167,1,187,5,236,11,106,166,132,168,11,89,116,218,18,192,251,109,96,224,6,137,183,33,40,237,48,16,157,104,130,92,9,120,161,140,35,40,233,20,237,110,44,237,12,193,145,209,199,120,221,61,63,142,139,50,249,61,59,191,52,187,24,128,174,183,66,43,25,144,122,136,81,27,86,237,243,190,55,132,91,98,130,176,223,17,58,56,0,0,0,0,0,0,0,0])
]
const webpBlob = new Blob(webp, { type: 'image/webp' })
// 生成链接打开该图片
URL.createObjectURL(webpBlob)

在浏览器中,可通过 URL.createObjectURL(blob) 为 Blob 生成链接,可直接在浏览器打开。

URL.createObject(blob)

FileReader API

这是最常用处理上传文件的 API,但是却繁琐冗余难记,每次使用基本上都要查文档!

FileReader API 用以读取 File/Blob 内容,正因为繁琐难记,以下实现一个 readBlob 函数读取内容。

function readBlob (blob) {
  return new Promise(resolve => {
    const reader = new FileReader()
    reader.onload = function (e) {
      resolve(new Uint8Array(e.target.result))
    }
    reader.readAsArrayBuffer(blob)
  })
}

Fetch API 中的 body 类型

事实上,在 fetch APIbody 中可直接接受 Blob 等,除此之外,还有 ReadableStream/FormData/URLSearchParams 等。

通过 typescript 可查看 body 可接受的类型。

// 对某些 API 不熟可直接跳过
type BodyInit = ReadableStream | Blob | ArrayBuffer | ArrayBufferView | FormData | URLSearchParams | string;
await fetch('/upload-jpeg', {
  body: blob,
  headers: {
    'content-type': 'image/jpeg'
  }
})

代码

实践见 http.devtool.tech/demo/upload 文档可在 Apifox 查看:

文件上传

作业

  1. 如何上传图片
  2. 如何上传 PDF