本篇文章针对: 前端非表单上传, 文件路径直接上传
按OSS的教程, 对于一些简单上传, 都很轻松接入
对于一些另类的上传, 如:
- 移动端[语音]上传
- 针对非表单上传, 文件路径转化成资源上传
网上大多教程要么就是让后端上传, 这是累死服务端的节奏~
对象介绍
- Blob
- File
- DataURI
- FormData
HTML 内置的 type=file, 应该是 input 家族里面大哥
吧, 它做了很多读取文件信息的事情, 有了它, 方便了文件上传, 按照规定它读取了文件大小, 修改时间, 类型 和名称
它包含了一个 FILELIST 里面是 FILE 对象
FILE 对象可以是:
1. 在一个<input>
元素上选择文件后返回的FileList
对象
2. 也可以来自拖放操作生成的DataTransfer
对象
3. 还可以是来自在一个HTMLCanvasElement
上执行mozGetAsFile()
方法后返回结果
针对计算机上的文件, 大哥身先士卒, 提供了 type=file 就搞定了读取文件这种累死人的活, 但很多时候, 还是要靠你自己干啊...
比如说: 发个语音, 把语音存到 OSS
语音说完会在临时区生成, 把文件上传到 oss 就用不了大哥那套了, 那只能我们自己去读取文件了.
FileReader对象: 允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据
// 读取File对象中的内容
var reader = new FileReader();
reader.onload = function (e) {
console.log(e.target.result);
};
reader.readAsDataURL(file); // file 为 blob 对象, data: URL格式的字符串以表示所读取文件的内容。
//详细看这里 https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
上面出现了 BLOB 和 data:URL 对象, 到底都是啥~
什么是Blob对象?简单来说, Blob 是 File 的老爹
Blob对象 存储着大量的二进制数据,并且 Blob 的 size 和 type 属性,都会被 File 对象所继承。同样FileReader对象也可以从Blob对象中读取数据。
一个 Blob对象表示一个不可变的, 原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式。 File 接口基于Blob,继承 blob功能并将其扩展为支持用户系统上的文件。
什么是URL对象? 简单来说, 就是用 base64 表达方式, 我们经常说把图片转成 base64, 就是这个对象, 当然不仅仅是图像
URL对象?
URL对象: 除了可以使用base64字符串作为内容的DataURI将一个文件嵌入到另外一个文档里,还可以使用URL对象。URL对象用于生成指向File对象或Blob对象的URL
objectURL = URL.createObjectURL(blob);
Blob很少主动生成, 一般都是用儿子FILE转化
转化篇
2020年02月13日23:02:13 更新
利用 fetch 轻松获取 blob
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
return response.blob();
}
throw new Error('Network response was not ok.');
}).then(function(myBlob) {
// do somethings here
// like
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ', error.message);
});
- DataUrl => Blob
// https://gist.github.com/fupslot/5015897
function dataURItoBlob(dataURI, callback) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var bb = new Blob([ab]);
return bb;
}
2. File Path to Blob 文件路径转 Blob
var oReq = new XMLHttpRequest();
oReq.open("GET", "/1.amr", true);
oReq.responseType = "blob";
oReq.onload = function(e) {
// 获取 blob
var blob = oReq.response;
}
oReq.send();
上传篇
上传到 oss, 阿里的 sdk 啥的写的太复杂了,咱简化下
- 为了安全, 向自身服务器获取ossToken
- 按 token 信息上传文件
var ossData = new FormData();
ossData.append("name", fileName); // 文件名字
ossData.append("key", filepathName); // 路径
ossData.append("policy", ossToken.policy); // 服务端获取 policy sts
ossData.append("OSSAccessKeyId", ossToken.accessid); // 服务端获取 accessid
ossData.append("signature", ossToken.signature); // 服务端 signature
ossData.append("success_action_status", 201);
// 注意, 阿里云这么上传没有问题, 某些golang语言的后台, 还是不支持blob的, 需要把blob转化成file
// var myfile = new File([blob], "name.png");
// ossData.append("file", myfile);
ossData.append("file", {blob});
var xhr = new XMLHttpRequest();
xhr.open("post", http://xxx.oss-cn-hangzhou.aliyuncs.com, true);
xhr.onload = () => {
xhr.abort();
// 上传成功
};
xhr.send(ossData);
做个技术补充:
在发送图片微博的微博的时候, 我们按正常情况是需要上传一张图片到微博, 然后进行发送, 我现在想通过类似花瓣, pinterest一键发送, 怎么解决图片上传问题?
首先说一下思路:
- 首先, 你在浏览页面获得了一张图片地址: http://img1001.pocoimg.cn/image/poco/works/99/2015/0830/00/1776503820150830001952050_17765038.jpg
2. 把图片转化成 base64
3. 将 base64 转化成 blob
4. 调用上传接口, 把 blob 上传
/**
* 工具类
*
* 2019年03月14日16:53:27
*/
export default {
trim: (s, maxLen = 20) => {
var minLength = 5;
if (maxLen < minLength) maxLen = minLength;
return s.length > maxLen ? s.substring(0, maxLen - 1) + "..." : s;
},
/* 获取 val */
val: e => {
return e.target.value;
},
getBase64PngImage: img => {
//console.log(img);
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
//return dataURL.replace(/^data:image/(png|jpg);base64,/, "");
return dataURL;
},
loadImg: url => {
var img = document.createElement("img");
img.onload = () => console.log(img);
img.onerror = e => console.log(e);
img.src = url;
return img;
},
dataURItoBlob: (dataURI, callback) => {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(",")[1]);
// separate out the mime component
// var mimeString = dataURI
// .split(",")[0]
// .split(":")[1]
// .split(";")[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var bb = new Blob([ab]);
return bb;
}
};
微博图片
微博图片的最大问题是防盗链
可以用
var img = new Image();
img.referrerpolicy = "no-referrer";
但是用了这个, 还是无法转 blob
提示 Tainted canvases may not be exported
解决办法是html2canvase