如何将文件从 URL 或服务器上的文件而不是文件输入附加到 FormData()

How to append a file to a FormData() from a URL or file on server rather than a file input

我正在使用 Stripe Connect API 编写一段代码,用户可以在其中将视觉效果从 input type="file" 发送到 AJAX 通过 jQuery 调用,这样:

var form_file = new FormData();
form_file.append('file', document.querySelector('input#file_to_send').files[0]);

当用户提交表单时,我通过 PHP 将视觉对象复制到服务器上的一个文件夹中,并将其名称保存在会话变量中。 如果表单中的某些内容不正确或缺失,用户将返回同一页面,其中视觉效果显示在 input type="file" 元素下方的 img 元素中,因此用户知道他们的视觉效果已考虑在内。

之后,我需要再次在 AJAX 调用中发送文件...除了这次,无法再从 input type="file" 选择文件,这是唯一可访问的来源我必须从 JavaScript.

中的 img 元素中获取它的名称

现在,如果我这样做:

var form_file = new FormData();
form_file.append('file', $('img#visual').attr('src'));

并通过相同的 AJAX 调用发送:

$.ajax({
    url: 'https://uploads.stripe.com/v1/files',
    type: 'POST',
    processData: false,
    contentType: false,
    headers: {'Authorization': 'Bearer xxxxxxxxxxxxxxxxx' },
    data: form_file
}).fail(function(e) {
    console.log('fail: ' + e);
}).done(function(e) {
    console.log('file uploaded: ' + e.id);
});

我的问题,您猜对了,是:有没有一种方法 to/how 我应该发送一个文件,而不是从 input 元素作为源,而是从img 元素?

我又看了一遍你的问题。如果我理解正确的话你需要发送跨域AJAX请求到stripe.com,这样你就不会控制服务器上的PHP代码边对吧?

简答:

最简单的方法是在 Javascript 而不是 PHP 中进行表单检查,这样您就不需要返回并“丢失”所选的输入文件。


...但是如果你真的need/want到发送跨域文件使用只有它的 URL,

然后您需要将 Data URI 转换为 File 然后附加到 FormData :

1/ 获取图片base64值

function toDataUrl(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
            callback(reader.result);
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.responseType = 'blob';
    xhr.send();
}

2/ 将base64图像转换为Blob:

function DataURIToBlob(dataURI: string) {
    const splitDataURI = dataURI.split(',')
    const byteString = splitDataURI[0].indexOf('base64') >= 0 ? atob(splitDataURI[1]) : decodeURI(splitDataURI[1])
    const mimeString = splitDataURI[0].split(':')[1].split(';')[0]

    const ia = new Uint8Array(byteString.length)
    for (let i = 0; i < byteString.length; i++)
       ia[i] = byteString.charCodeAt(i)

    return new Blob([ia], {
       type: mimeString
    })
 }

3/ 向您发送带有 FormData 的 Blob :

const file = DataURIToBlob(imgBase64)
const formData = new FormData();
formData.append('upload', file, 'image.jpg')

来源:


编辑:

您可以通过使用 Fetch API 直接获取图像 Blob 来加快阶段 1 和阶段 2。

(警告:与 IE 不兼容)

来源:

谢谢@e-telier!将您的代码示例与您建议的链接上的内容相结合后,我能够实现我想要的!这是我最终得到的代码:

var visual_source = 'upload/file-source.png';
var visual_ext = visual_source.split('.').pop();
var visual = await fetch(visual_source);
console.log(visual);
var visual_as_blob = await visual.blob();
console.log(visual_as_blob);
var visual_as_file = new File([visual_as_blob], 'file-name-renamed.' + visual_ext, { lastModified: new Date().getTime(), type: visual_as_blob.type });
console.log(visual_as_file);
form_file.append('file', visual_as_file);

如果有人需要此代码并希望逐步查看发生的结果,我会在每个步骤中添加一个 console.log()。步骤是:

  • 我们从给定的 url 中获取文件(这里是服务器上“上传”文件夹中的一个文件)
  • 我们将获取的数据设置为blob
  • 我们将 blob 转换为文件
  • 然后我们可以将文件追加到 FormData() 元素

之后,可以通过ajax发送到StripeAPI。

再次感谢您的帮助!! :))