基于form-data请求格式详解


Posted in Javascript onOctober 29, 2019

最近一直都比较忙,坚持月月更新博客的计划不得中止了,今天抽出点时间来说说最近项目中遇到的一个问题,有关request post请求格式中的multipart/form-data格式。

引言

最近在参与一个项目过程中遇到一个问题,相信大部分人都遇到过:

在后端与前端约定好application/json格式传递数据时,因为后台是go强类型语言,在定义api接口时,某些字段要求是整型类型,但是对于前端来说输入框或者从url中的search取到的参数都是字符串,不得不进行前端类型转换。

咋一看,对于接口参数比较少的api前端转换没有什么,但是对于一般的交互复杂,参数比较多的接口,要对大部分参数进行类型转换就是一种吃力不讨好的活。好在后端同学还支持另一种的前后端数据交互格式,即multipart/form-data。通过该格式后端取到前端传递的数据就是数字了(即使前端传递的是字符串),而不像json格式获取的是字符串。这样,就不需要额外对前端获取的数据进行特殊转换了。下面就来说说form-data。

form-data请求格式

multipart/form-data是基于post方法来传递数据的,并且其请求内容格式为Content-Type: multipart/form-data,用来指定请求内容的数据编码格式。另外,该格式会生成一个boundary字符串来分割请求头与请求体的,具体的是以一个boundary=${boundary}来进行分割,伪码如下:

...
Content-Type: multipart/form-data; boundary=${boundary} 

--${boundary}
...
...

--${boundary}--

上面boundary=${boundary}之后就是请求体内容了,请求体内容各字段之间以--${boundary}来进行分割,以--${boundary}--来结束请求体内容。

具体可以参考下面例子:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyb1zYhTI38xpQxBK

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="city_id"

1

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="company_id"

2
------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryyb1zYhTI38xpQxBK--

form-data格式一般是用来进行文件上传的。使用表单上传文件时,必须让

表单的 enctype 等于 multipart/form-data,因为该值默认值为application/x-www-form-urlencoded。

FormData对象

XMLHttpRequest Level 2添加了一个新的接口FormData。利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单"。

var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456); 
fetch('/users', {
 method: 'POST',
 body: formData
})

上面创建了一个FormData对象,通过fetch进行ajax请求时,会自动为其将其转为form-data格式,无需手动添加格式。

对象转FormData对象

对于FormDat对象,像上面那种形式可以直接添加参数比较方便,但是对于对象或者嵌套对象:

let userObj = {userName: 'xxx', age: '21'} formData.append('user', userObj)

上面形式添加formData参数user,并不会获取到其真正的内容,而是返回userObj的Object.prototype.toString.call(userObj)的值作为user字段的值。

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="user"

[object Object]

遗憾的是,FormData对象没有像JSON.stringify那样的方法能批量将对象形式转换为对应的形式,formData而言是将对象的key转换为正确formData请求参数字段名,例如如下对象:

var obj = {
  a: '2', 
  b: {c: 'test'}, 
  c: [ 
    {id: 1, name: 'xx'}, 
    {id:2 ,name: 'yy', info: {d: 4} }
  ]
}

这样转换为FormData对象时,其对应的key应该是下面这样的:

a: 2
b[c]: test
c[][id]: 1
c[][name]: xx
c[][id]: 2
c[][name]: yy
c[][info][d]:4

这样,就需要我们自己手动来实现一个转换数据函数,具体代码如下:

function objectToFormData (obj, form, namespace) {
 const fd = form || new FormData();
 let formKey;
 
 for(var property in obj) {
   if(obj.hasOwnProperty(property)) {
    let key = Array.isArray(obj) ? '[]' : `[${property}]`;
    if(namespace) {
     formKey = namespace + key;
    } else {
     formKey = property;
    }
   
    // if the property is an object, but not a File, use recursivity.
    if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
     objectToFormData(obj[property], fd, formKey);
    } else {
     
     // if it's a string or a File object
     fd.append(formKey, obj[property]);
    }
    
   }
  }
 
 return fd;
  
}

这样,就可以将对象转化为对应的formData的格式了。

以上这篇基于form-data请求格式详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 使FORM表单的所有元素不可编辑的示例代码
Oct 17 Javascript
Jquery easyUI 更新行示例
Mar 06 Javascript
javascript制作sql转换为stringBuffer的小工具
Apr 03 Javascript
全面解析Bootstrap中transition、affix的使用方法
May 30 Javascript
浅谈JS的基础类型与引用类型
Sep 13 Javascript
JavaScript的new date等日期函数在safari中遇到的坑
Oct 24 Javascript
AngularJS深入探讨scope,继承结构,事件系统和生命周期
Nov 02 Javascript
微信小程序 五星评价功能的实现
Mar 09 Javascript
p5.js入门教程之小球动画示例代码
Mar 15 Javascript
Vue在页面右上角实现可悬浮/隐藏的系统菜单
May 04 Javascript
vue弹窗组件的实现示例代码
Sep 10 Javascript
vue webpack build资源相对路径的问题及解决方法
Jun 04 Javascript
解决vue-cli项目开发运行时内存暴涨卡死电脑问题
Oct 29 #Javascript
JS操作字符串转数字的常见方法示例
Oct 29 #Javascript
Vue axios 将传递的json数据转为form data的例子
Oct 29 #Javascript
详解Vue 项目中的几个实用组件(ts)
Oct 29 #Javascript
JS操作json对象key、value的常用方法分析
Oct 29 #Javascript
JQuery 实现文件下载的常用方法分析
Oct 29 #jQuery
Vue 设置axios请求格式为form-data的操作步骤
Oct 29 #Javascript
You might like
PHP和Mysqlweb应用开发核心技术-第1部分 Php基础-2 php语言介绍
2011/07/03 PHP
php重定向的三种方法分享
2012/02/22 PHP
关于zend studio 出现乱码问题的总结
2013/06/23 PHP
php图片处理函数获取类型及扩展名实例
2014/11/19 PHP
PHP消息队列用法实例分析
2016/02/12 PHP
Zend Framework教程之动作的基类Zend_Controller_Action详解
2016/03/07 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
2016/09/09 PHP
php打开本地exe程序,js打开本地exe应用程序,并传递相关参数方法
2018/02/06 PHP
浅谈Javascript事件模拟
2012/06/27 Javascript
别了 JavaScript中的isXX系列
2012/08/01 Javascript
jquery foreach使用示例
2013/09/12 Javascript
file控件选择上传文件确定后触发的js事件是哪个
2014/03/17 Javascript
node.js中使用q.js实现api的promise化
2014/09/17 Javascript
Angularjs中使用Filters详解
2016/03/11 Javascript
js基础之DOM中document对象的常用属性方法详解
2016/10/28 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
vue事件修饰符和按键修饰符用法总结
2017/07/25 Javascript
Node.js中使用mongoose操作mongodb数据库的方法
2017/09/12 Javascript
微信小程序实现商城倒计时
2020/11/01 Javascript
python实现删除文件与目录的方法
2014/11/10 Python
python3.5使用tkinter制作记事本
2016/06/20 Python
详解Python多线程Selenium跨浏览器测试
2017/04/01 Python
Anaconda入门使用总结
2018/04/05 Python
Jupyter中直接显示Matplotlib的图形方法
2018/05/24 Python
python爬取网易云音乐评论
2018/11/16 Python
Python控制键盘鼠标pynput的详细用法
2019/01/28 Python
python 实现返回一个列表中出现次数最多的元素方法
2019/06/11 Python
浅谈Python线程的同步互斥与死锁
2020/03/22 Python
Pytorch学习之torch用法----比较操作(Comparison Ops)
2020/06/28 Python
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
英国领先的隐形眼镜在线供应商:Lenstore.co.uk
2019/11/24 全球购物
Vans(范斯)新西兰官方网站:美国原创极限运动品牌
2020/09/19 全球购物
运动会入场式解说词
2014/02/18 职场文书
预防艾滋病宣传标语
2014/06/25 职场文书
培训班开班主持词
2015/07/02 职场文书
为什么node.js不适合大型项目
2021/04/28 Javascript