使用 Javascript(或 Angular)在每个部分上使用不同的 Content-Type 组合 multipart/form-data

Posted

技术标签:

【中文标题】使用 Javascript(或 Angular)在每个部分上使用不同的 Content-Type 组合 multipart/form-data【英文标题】:Composing multipart/form-data with a different Content-Type on each parts with Javascript (or Angular) 【发布时间】:2014-08-23 11:37:52 【问题描述】:

提出了错误的问题,请参阅下面的更新

我需要将我的 AngularJS 项目与现有的 RESTful API 集成。这些 API 使用 upload a file 的 POST 请求,并在请求中提交表单数据。不幸的是,其中一个表单输入需要在Content-Type: Application/json 中。

在网上搜索后,我只能POSTContent-Type: multipart/form-data,其中每个部分都没有特定的MIME。 如何在 javascript 中为每个部分使用不同的 MIME 组合我的 multipart/form-data

POST /api/v1/inventory
Host: localhost:8000
Origin: http://localhost:9000
Content-Type: multipart/form-data; boundary=------border

------border
Content-Disposition: form-data; name="owner"

john doe
------border
Content-Disposition: form-data; name="image"; filename="mybook.png"
Content-Type: image/png


------border
Content-Disposition: form-data; name="items"
Content-Type: application/json

"name": "Book", "quantity": "12"
------border--

相关参考资料:

    https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects REST - HTTP Post Multipart with JSON http://code.activestate.com/recipes/578846-composing-a-postable-http-request-with-multipartfo/ application/x-www-form-urlencoded or multipart/form-data? https://***.com/a/9082243/764592

更新

为提出错误的问题道歉。原来的问题是,我可以看到服务器调用了类似的逻辑,

func POST(req):
     owner = req.owner // This is string
     image = req.image // This is file object
     itemQuantity = req.items.quantity // Items is an object with attribute quantity
     itemName = req.items.name // Items is an object with attribute name

我还设法弄清楚如何提交这样的帖子请求。我将在下面发布我的答案。

再次抱歉问错了问题。

【问题讨论】:

该 API 目前与移动应用程序一起使用。如果移动应用程序可以生成这样的请求,我相信网络浏览器也应该能够编写这些请求。 参考 5. 显示我们应该能够编写此类请求的规范。 不确定我是否必须为此从头开始创建自定义 XMLHttpRequest? developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest 这个问题应该被关闭,因为它是一个错误的问题。 【参考方案1】:

根据FormData的文档,您可以使用Blob构造函数追加具有特定内容类型的字段:

var formData = new FormData();

formData.append('items', new Blob([JSON.stringify(
    name: "Book",
    quantity: "12"
)], 
    type: "application/json"
));

经过仔细观察,原来它会发送部分如下:

Content-Disposition: form-data; name="items"; filename="blob"
Content-Type: text/json

唯一可以避免自己构建整个请求的替代方法是传递一个字符串值:

formData.append('items', '"name": "Book", "quantity": "12"');

很遗憾,这并没有设置 Content-Type 标头。

【讨论】:

虽然它设置了Content-Type: 'application/json',但它仍然被包裹在一个Blob下。因此,API 拒绝了我的请求。 gist.github.com/9gix/… 我之前评论的结果是基于 Blob 的正确语法。 @Yeo 你也试过formData.append('items', JSON.stringify(...)) 吗? 因为我使用的是 Angular,因此这是我用来转换为 JSON angular.toJson() 的东西,我相信它会做同样的事情。 docs.angularjs.org/api/ng/function/angular.toJson Yeap 使用 blob: var blob = new Blob([JSON.stringify(requestVo)], type: "application/json" ) formData.append('data',blob); 【参考方案2】:

错误 #1:我错误地认为 items 必须是 json,以便我们可以调用它的属性。

解决方案:提交包含文件和类似格式的对象的多部分请求非常简单。

form = new FormData();
form.append('items[name]', 'Book');
form.append('items[quantity]', 12);
form.append('image', imageFile);
form.append('owner', 'John Doe');

因此,请求标头和正文看起来像这样

POST /api/v1/inventory
Host: localhost:8000
Origin: http://localhost:9000
Content-Type: multipart/form-data; boundary=------border

------border
Content-Disposition: form-data; name="owner"

john doe
------border
Content-Disposition: form-data; name="image"; filename="mybook.png"
Content-Type: image/png


------border
Content-Disposition: form-data; name="items[name]"

Book
------border
Content-Disposition: form-data; name="items[quantity]"

12
------border--

【讨论】:

啊,你拯救了我的一天。我还假设 json 必须像常规发布数据一样位于单个对象中!谢谢。【参考方案3】:

在我将Content-Type 标头设置为未定义之前,没有什么可以让它工作。就我而言,我正在发布一个文件和一些 json。

public uploadFile(code: string, file):angular.IHttpPromise<any>
    var data = `"query":"mutation FIRMSCORECARD_CALCULATE($code:String!) FirmScorecardMutation BatchCalculate(Code:$code) ","variables":"code":"$code","operationName":"FIRMSCORECARD_CALCULATE"`;
    var formData = new FormData();
    formData.append('operations', data);
    formData.append('file', file, file.name);

    let config = 
        headers: 
            'Accept': 'application/json',
            'Content-Type': undefined
        
    ;
    let response = this.$http.post(this.graphqlUrl, formData, config);
    return response;

【讨论】:

以上是关于使用 Javascript(或 Angular)在每个部分上使用不同的 Content-Type 组合 multipart/form-data的主要内容,如果未能解决你的问题,请参考以下文章

使用 Express 时未加载 Javascript (Angular)

使用 Javascript(或 Angular)在每个部分上使用不同的 Content-Type 组合 multipart/form-data

如何使用 angular 2 或 javascript 从客户端计算机获取日期和时间格式?

如何在 Angular 8 或 javascript 中明智地获取当前日期每周日

.Net Blazor 优于 Angular、React 或其他 javascript 框架 [关闭]

typescript 以javascript或angular格式化日期