发送请求上传文件

595 阅读2分钟

记录一下自己一直以来的疑惑,文件上传类的请求如何去做模拟?

首先了解一下上传的文件的逻辑,本地文件通过浏览器上传,其实传输的是二进制数据。

我们可以通过一张图来了解下,这是在chrome devtools下看到的样子:

重点看这里的file:binary。这里所描述的就是二进制数据。在过去,这里的东西我们是没办法动的,因为js没有提供过一些二进制的操作方式。然而在现代的浏览器当中,文件操作变得触手可及。

与文件操作相关联的三个东西

  • BASE64,通过64个字符编码的文件地址,可以再浏览器中以地址的形式呈现文件。

  • Blob,里面就是我们平时储存的二进制数据。

  • File,上传时候的File文件对象

然后它们之间相互转换的关系如下:

//base64转blob对象
function dataURLtoBlob(dataurl) {
    var arr = dataurl.split(","),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
  }

//Blob转base64
function blobToDataURL(blob, callback) {
    let a = new FileReader();
    a.onload = function (e) { callback(e.target.result); }
    a.readAsDataURL(blob);
}

//Blob转file
let files = new window.File([blob], 文件名, {type:文件类型})

另外要了解的一个是 Fromdata:

fromdata是可以在js中模拟表单提交操作,区别于Query string Parameters 。

了解了这些之后,我们可以来谈谈上传思路:

  • 前提条件,A网站的图片搬到B网站上传:

    • 使用fetch直接请求图片到blob数据,关闭跨域则看我这篇文章。不行的话只能node启动服务来生成base64再转blob。

    • 发送请求:

      • var data = new FormData();
        data.append("file", blob或者file对象);
        $.ajax({
            url:
              "地址",
            type: "POST",
            data: data,
            success: function(data) {
                console.log(data)
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
              alert("上传失败,请检查网络后重试");
            }
          });
        
  • 前提条件,本地图片搬到网站上传:

    • Node生成blob数据或者buffer,然后跟上面例子一样即可。

浏览器ajax本地文件方法:

谷歌浏览器启动参数加上:--allow-file-access-from-files使用 chrome://version查看生效的启动参数 然后重启整个浏览器(请求只支持ajax,不支持fetch)

//获取到本机文件二进制
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.open('get','本地文件地址')
xhr.send()

利用file api 转化为window.file文件,这样的话可以控制文件名

new window.File([xhr.response],'测试文件.jpg')

然后再利用fromdata进行文件上传:

var xhr2 = new XMLHttpRequest();
xhr2.open('POST','XXXXXX')
xhr2.send(new FromData())

File、Blob、ArrayBuffer等文件类的对象有什么区别和联系 聊聊JS的二进制家族:Blob、ArrayBuffer和Buffer