将 JS 对象转换为表单数据

IT技术 javascript jquery multipartform-data form-data
2021-01-14 06:05:42

如何将我的 JS 对象转换为FormData?

我想要这样做的原因是,我有一个对象,它是从大约 100 个表单字段值中构造出来的。

var item = {
   description: 'Some Item',
   price : '0.00',
   srate : '0.00',
   color : 'red',
   ...
   ...
}

现在我被要求将上传文件功能添加到我的表单中,这当然不可能通过 JSON 实现,所以我计划转移到FormData. 那么有什么方法可以将我的 JS 对象转换为FormData

6个回答

如果您有一个对象,您可以轻松创建一个 FormData 对象并将该对象的名称和值附加到 formData。

您还没有发布任何代码,所以这是一个通用示例;

var form_data = new FormData();

for ( var key in item ) {
    form_data.append(key, item[key]);
}

$.ajax({
    url         : 'http://example.com/upload.php',
    data        : form_data,
    processData : false,
    contentType : false,
    type: 'POST'
}).done(function(data){
    // do stuff
});

MDN上的文档中有更多示例

将复杂的 json 对象(包含嵌套对象和数组)转换为 FormData 对象的方法是什么?
2021-03-25 06:05:42
@Lior - 如果您的服务器在 POST 请求中收到另一个键/值对时出现故障,那么您就做错了。我认为答案很好,我不会更改它以使用Object.keyshasOwnProperty()因为对象已发布在问题中并且不需要任何这些。您有时会hasOwnProperty在插件等中看到使用的原因是因为您永远不知道有些人可能会对Object构造函数做什么,但在大多数情况下,人们不应该测试他们创建的对象的继承属性,这是一个迹象你可能做错了什么。
2021-03-28 06:05:42
@Lior -item是由 OP 创建的常规对象,因此它不应该具有任何不属于它自己的属性,除非有人错误地将某些东西原型化到 Object 构造函数上,在这种情况下,您将陷入困境,这不是我们应该防范的。
2021-03-29 06:05:42
当然会,你不知道服务器在期待什么......因为......在JS中是有问题的,解决方案不一定是Object.keys(),它可以是hasOwnProperty(),但是它至少需要是一个警告。
2021-03-29 06:05:42
@Lior - 它只是将键/值对添加到 FormData,添加原型属性不会破坏任何东西,并且使用Object.keys不是答案,因为您不必将键作为数组获取,然后遍历键来获取值,您应该使用for..in循环。
2021-04-13 06:05:42

使用 ES6 和更多函数式编程方法@adeneo 的答案可能如下所示:

function getFormData(object) {
    const formData = new FormData();
    Object.keys(object).forEach(key => formData.append(key, object[key]));
    return formData;
}

或者使用.reduce()和箭头函数:

const getFormData = object => Object.keys(object).reduce((formData, key) => {
    formData.append(key, object[key]);
    return formData;
}, new FormData());
我刚刚对您的两个答案进行了性能比较,.reduce()其中一个快了 1-2%。jsbench.me/m3kg87fxvt/1
2021-03-15 06:05:42

此函数将对象中的所有数据添加到 FormData

来自@developer033 的 ES6 版本:

function buildFormData(formData, data, parentKey) {
  if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => {
      buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
    });
  } else {
    const value = data == null ? '' : data;

    formData.append(parentKey, value);
  }
}

function jsonToFormData(data) {
  const formData = new FormData();
  
  buildFormData(formData, data);
  
  return formData;
}

const my_data = {
  num: 1,
  falseBool: false,
  trueBool: true,
  empty: '',
  und: undefined,
  nullable: null,
  date: new Date(),
  name: 'str',
  another_object: {
    name: 'my_name',
    value: 'whatever'
  },
  array: [
    {
      key1: {
        name: 'key1'
      }
    }
  ]
};

jsonToFormData(my_data)

jQuery 版本:

function appendFormdata(FormData, data, name){
    name = name || '';
    if (typeof data === 'object'){
        $.each(data, function(index, value){
            if (name == ''){
                appendFormdata(FormData, value, index);
            } else {
                appendFormdata(FormData, value, name + '['+index+']');
            }
        })
    } else {
        FormData.append(name, data);
    }
}


var formData = new FormData(),
    your_object = {
        name: 'test object',
        another_object: {
            name: 'and other objects',
            value: 'whatever'
        }
    };
appendFormdata(formData, your_object); 
对我来说效果很好,我添加了 if (typeof data === 'object' && data !== null){ 因为如果值为 null,它会抛出异常
2021-03-15 06:05:42
效果很好!谢谢!我还必须&& !(data instanceof Blob)在我的案例中添加上传我的图片
2021-03-17 06:05:42
对于 ES6 版本,我添加&& !(Array.isArray(data) && !data.length)了“if”条件,否则将删除空数组。
2021-03-17 06:05:42
这是天才。非常漂亮地解决了我的问题。
2021-03-25 06:05:42
不错 坚持下去
2021-04-01 06:05:42

试试下面的 JSON.stringify 函数

var postData = JSON.stringify(item);
var formData = new FormData();
formData.append("postData",postData );
这是实现这一目标的最佳方式。
2021-03-18 06:05:42
这不适用于 .net,您需要在附加字符串中添加属性,例如 formData.append('doneWorks[0].description',data.doneWorks[0].description)
2021-03-31 06:05:42
在多次错误调试后,它会继续附加 json
2021-04-06 06:05:42
超级、简单和排序的解决方案。节省了我的时间。
2021-04-07 06:05:42
这行不通,因为在发送 formdata 时它被转换为字符串,意味着两次字符串化
2021-04-13 06:05:42

其他答案对我来说是不完整的。我从@Vladimir Novopashin 的答案开始并对其进行了修改。以下是我需要的东西和我发现的错误:

  • 支持文件
  • 支持数组
  • 错误:复杂对象中的文件需要添加.prop而不是[prop]. 例如,formData.append('photos[0][file]', file)没有在谷歌浏览器上工作,而 formData.append('photos[0].file', file)工作
  • 忽略对象中的某些属性

以下代码应该适用于 IE11 和常绿浏览器。

function objectToFormData(obj, rootName, ignoreList) {
    var formData = new FormData();

    function appendFormData(data, root) {
        if (!ignore(root)) {
            root = root || '';
            if (data instanceof File) {
                formData.append(root, data);
            } else if (Array.isArray(data)) {
                for (var i = 0; i < data.length; i++) {
                    appendFormData(data[i], root + '[' + i + ']');
                }
            } else if (typeof data === 'object' && data) {
                for (var key in data) {
                    if (data.hasOwnProperty(key)) {
                        if (root === '') {
                            appendFormData(data[key], key);
                        } else {
                            appendFormData(data[key], root + '.' + key);
                        }
                    }
                }
            } else {
                if (data !== null && typeof data !== 'undefined') {
                    formData.append(root, data);
                }
            }
        }
    }

    function ignore(root){
        return Array.isArray(ignoreList)
            && ignoreList.some(function(x) { return x === root; });
    }

    appendFormData(obj, rootName);

    return formData;
}
唯一支持数组、对象和文​​件的答案。
2021-03-17 06:05:42
我正在尝试使用它,但没有使用示例。ignoreList 参数的预期格式会很有帮助。
2021-03-20 06:05:42
嗨,为什么要将文件添加到根目录?是否也可以将其添加到 child 中?
2021-03-30 06:05:42
@CedricArnould 这可能是一种误解,但该方法是递归的,因此即使它已写入formData.append(root, data),也不意味着它已添加到根目录中。
2021-04-09 06:05:42
我理解你的回答,奇怪的是当我在服务器中得到结果时,我有一个独特的文件集合和数据。但是我可以在文件中看到名称给出了它所连接的孩子的信息。也许问题来自 .Net Core 以及它如何管理上传文件。感谢您的回答。
2021-04-13 06:05:42