项目中,一般都是将本地图片上传给服务器,但是最近项目中,居然遇到要将远程获取的图片(url链接)再次上传给服务器的需求。
好嘛,挑战又来了!
最终,经过一番查搜与实践,终于找到了实现方案。
因为后端上传接口中的file参数需以文件流的形式上传,所以我们如果想正确上传,那就需要将手里的imgUrl通过某种方式转为文件流。
那如果将imgUrl转为文件流呢?
需要经历如下两步:
一: 将imgUrl 转 base64Url
将imgUrl转为base64Url,我亲测了两种方式(还有其他方法欢迎评论区补充),均可实现。
方式1:利用canvas + Image() 实现
function imgUrlToBase64(imgUrl) {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.crossOrigin = 'Anonymous';// 允许跨域
img.src = imgUrl
img.onload = function() {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img,0,0);
const dataURL = canvas.toDataURL('image/png');
resolve(dataURL)
canvas = null;
}
img.onerror = function (err) {
reject(err)
}
})
}
注意:
后端需给图片服务器配置Access-Control-Allow-Origin信息,前端需设置crossOrigin属性为anonymous,不然会出现跨域问题。
方式二:利用ajax + FileReader() 实现
function imgUrlToBase64(imgUrl) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("get", imgUrl, true);
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status == 200) {
const blob = this.response;
const fileReader = new FileReader();
fileReader.onloadend = function (e) {
resolve(e.target.result)
};
fileReader.readAsDataURL(blob)
}
}
xhr.send();
})
}
注意:此方法虽然没有跨域问题,但因为是blob地址,所以图片不宜过大,否则超过blob尺寸限制就会有问题。
二:将base64Url转为文件流
将imgUrl转为base64Url后,我们再通过如下方法,将base64Url转为二进制文件流。
function base64Tofile(base64Url,fileName) {
const arr = base64Url.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
//转换成file对象
return new File([u8arr], fileName, {type: mime});
//转换成成blob对象
//return new Blob([u8arr],{type: mime});
}
经历以上两步后,我们调取后端上传接口,把file以参数形式传过去就能将远程图片上传到服务器了。伪代码如下:
const base64Url = await this.imgUrlToBase64(imgUrl)
const file = await this.base64Tofile(base64Url, '图片1.png')
const formData = new FormData()
formData.append('file', file)
formData.append('type', 1) // 关系类型
formData.append('filePath', 'follow-record')
const contextType = { 'Content-Type': 'multipart/form-data' }
// 上传接口
uploadFile(formData, contextType)
以上方式,如有不足,欢迎指正!