基于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 相关文章推荐
AJAX 网页保留浏览器前进后退等功能
Feb 12 Javascript
无缝滚动js代码通俗易懂(自写)
Jun 19 Javascript
jQuery新的事件绑定机制on()示例应用
Jul 18 Javascript
分享两个手机访问pc网站自动跳转手机端网站代码
Dec 24 Javascript
JavaScript中的Math.LOG2E属性使用详解
Jun 14 Javascript
jQuery实现微信长按识别二维码功能
Aug 26 Javascript
jQuery EasyUI ProgressBar进度条组件
Feb 28 Javascript
Vue实现路由跳转和嵌套
Jun 20 Javascript
AngualrJs清除定时器遇到的坑
Oct 13 Javascript
Vue写一个简单的倒计时按钮功能
Apr 20 Javascript
vue 开发企业微信整合案例分析
Dec 02 Javascript
js回到页面指定位置的三种方式
Dec 17 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 字符截取 解决中文的截取问题,不用mb系列
2009/09/29 PHP
基于php无限分类的深入理解
2013/06/02 PHP
php生成缩略图填充白边(等比缩略图方案)
2013/12/25 PHP
php array_merge函数使用需要注意的一个问题
2015/03/30 PHP
PHP提高编程效率的20个要点
2015/09/23 PHP
php批量删除超链接的实现方法
2015/10/19 PHP
php获取ip及网址的简单方法(必看)
2017/04/01 PHP
PHP实现SMTP邮件的发送实例
2018/09/27 PHP
javascript学习笔记(七) js函数介绍
2012/06/19 Javascript
jQuery验证插件validation使用指南
2015/04/21 Javascript
javascript html5 canvas实现可拖动省份的中国地图
2016/03/11 Javascript
基于jquery实现百度新闻导航菜单滑动动画
2016/03/15 Javascript
jQuery实现点击弹出背景变暗遮罩效果实例代码
2016/06/24 Javascript
Vue.js第二天学习笔记(vue-router)
2016/12/01 Javascript
详解JavaScript模块化开发
2016/12/04 Javascript
详解jQuery简单的表格应用
2016/12/16 Javascript
轻松玩转BootstrapTable(后端使用SpringMVC+Hibernate)
2017/09/06 Javascript
浅谈vue项目如何打包扔向服务器
2018/05/08 Javascript
vue-router 源码之实现一个简单的 vue-router
2018/07/02 Javascript
详解vue中axios的使用与封装
2019/03/20 Javascript
Swiper.js实现移动端元素左右滑动
2019/09/08 Javascript
[01:13]这,就是刀塔
2014/07/16 DOTA
Python实现批量下载图片的方法
2015/07/08 Python
使用Python多线程爬虫爬取电影天堂资源
2016/09/23 Python
如何用Python合并lmdb文件
2018/07/02 Python
Python绘图实现显示中文
2019/12/04 Python
python FTP批量下载/删除/上传实例
2019/12/22 Python
Python concurrent.futures模块使用实例
2019/12/24 Python
Django调用百度AI接口实现人脸注册登录代码实例
2020/04/23 Python
给keras层命名,并提取中间层输出值,保存到文档的实例
2020/05/23 Python
用HTML5 Canvas API中的clearRect()方法实现橡皮擦功能
2016/03/15 HTML / CSS
Canvas环形饼图与手势控制的实现代码
2019/11/08 HTML / CSS
工地质量标语
2014/06/12 职场文书
关于九一八事变的演讲稿2014
2014/09/17 职场文书
2016大学先进团支部事迹材料
2016/03/01 职场文书
在Centos 8.0中安装Redis服务器的教程详解
2022/03/21 Redis