如何正确将文件附加到formData中并在发送POST请求到服务器之前?

5

我一直在跟随这个 FormData教程, 但是我还没有理解 formData对象的工作原理。

我的输入表单

enter image description here

<input type="file" id="file-id" class="w300px rounded4px" name="file" placeholder="PDF file">
<button class="btn-upload-pdf" ng-click="asub.uploadPDF()">Upload</button>

这是上传按钮功能:

this.uploadPDF = () => {
    const formData = new FormData();
    const fileInput = document.getElementById('file-id');
    const file = fileInput.files[0];
    formData.append('pdf-file', file);
    console.log('formData', formData)

    return ApiFactory.insightPDF(formData).then((res) => {
        console.log('res', res);
        return res;
    });
};

当我注销fileInput对象.files[0]时,我可以看到刚刚附加的文件:

enter image description here

似乎这意味着这个对象应该足以发送到POST。 但是这是下一步:
formData.append('pdf-file', file);
我在将其发送到我的工厂之前记录了formData,这是结果,我没有看到键“pdf-file”或PDF文件的任何地方,只有一堆方法? 文件被添加到哪里? formData如何包含实际的PDF?

enter image description here

我需要附加formData对象中的某些内容:

发送POST请求的工厂

const insightPDF = (formData) => {
    console.log(' formData', formData)
    return $http.post('/app/api/insights_pdf', formData).then((res) => {
        console.log('PDF uploaded res', res)
        return res;
    }).catch(apiError);
};

你应该使用 fromData 而不是 file 进行发布。 - jbrown
啊,抱歉,我是从Data中发布的,当我在“insightPDF”函数内部时,我只是将变量名更改为file,我应该将其改回去。 - Leon Gaban
1个回答

6

设置Content-Type: undefined

当发布由 FormData API创建的对象时,重要的是将内容类型标头设置为undefined

const insightPDF = (formData) => {
    console.log(' formData', formData)
    var config = { headers: {'Content-Type': undefined} };
    return $http.post('/app/api/insights_pdf', formData, config)
     .then((res) => {
        console.log('PDF uploaded res', res)
        return res;
    }).catch(apiError);
};

通常情况下,AngularJS框架会自动将内容类型标头添加为application/json,这将覆盖XHR Send()方法设置的内容类型。当XHR API发送FormData对象时,它会自动设置内容类型为multipart/form-data,并带有适当的边界值。
来自文档:

The $http service will automatically add certain HTTP headers to all requests

To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, Use the headers property, setting the desired header to undefined. For example:

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': undefined
 },
 data: { test: 'test' }
}

— AngularJS $http Service API Reference - Setting HTTP Headers

FormData对象Blob对象一样,都是JavaScript中非本地定义的宿主对象。并非所有属性都可以通过console.logconsole.dir查看。文件是Blob类型的一种特殊类型。数据不一定从磁盘加载。通常,数据仅在特定API需要时才从磁盘流式传输。


避免额外开销--直接发送文件

multipart/form-data 类型的内容使用 base64编码,会增加33%的额外开销。如果只上传一个文件,直接发送文件 blob 更为高效。

//MORE Efficient; Avoids base64 encoding overhead

const insightPDF = (dataObject) => {
    var config = { headers: {'Content-Type': undefined} };
    return $http.post('/app/api/insights_pdf', dataObject, config)
     .then((res) => {
        console.log('PDF uploaded res', res)
        return res;
    }).catch(apiError);
};

var file = inputElem[0].files[0];
insightPDF(file);

如果服务器可以直接接受二进制内容,最好以这种方式发送文件。 XHR API将自动将内容类型设置为文件类型。

谢谢!没有更多错误了...现在只需要完成后端端点 :) 有没有办法看到文件在FormData对象中的附加位置?当我记录它时,它仍然只是一堆方法。formData.append('pdf-file', file);是做什么用的? - Leon Gaban
正如我在答案中所说,formData对象是宿主环境对象。它是一个外来的非本地代理,用于处理宿主环境中的事物。JavaScript只能看到语言可用的方法和属性。底层有更多内容。Web API,如FileReaderXHR send,在底层与宿主环境的方法和属性有连接。 - georgeawg
要查看FormData对象中附加了什么,请使用formData.entries()方法。有关示例,请参见form data is not appending file object - georgeawg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接