【问题标题】:FormData append nested objectFormData 附加嵌套对象
【发布时间】:2019-03-05 02:24:56
【问题描述】:

是否可以将嵌套对象附加到FormData?

let formData = new FormData();
let data = {
    title: 'title',
    text: 'text',
    preview: {p_title:'p title', p_text: 'p text'}
};

$.each(data, function(key, value) {
    formData.append(key, value);
});

服务器控制台 - console.log(req.body)

{
    title: 'title',
    text: 'text',
    preview: '[object Object]'
}

我怎样才能得到preview: {p_title:'p title', p_text: 'p text'}的确切值?

【问题讨论】:

  • 你真的需要服务器端的这种结构吗?在这种情况下,您必须遍历您的对象并使用key[subkey] 表示法,例如formData.append('preview[p_title]', 'p title');。但除此之外,只需将其作为 JSON 字符串发送并在服务器端解析它,通常是最简单的发送和检索。
  • 其实我是后端编码新手,我的mongodb结构是嵌套的,为什么我从客户端选择这个结构来发送数据,我认为这是正确的方法,我认为最简单的方法不要尝试通过来自客户端的嵌套结构,只是在我发送到 db @Kaiido 之前从服务器重新构建结构

标签: javascript jquery json node.js form-data


【解决方案1】:

首先我为我糟糕的英语道歉。

我做了一些事情以在服务器端正确获取数据,而不是在我写入控制台时。我希望你愿意这样做。

我必须编写一个 javascript 函数来获取服务器端的客户端嵌套数据。

为此,我编写了 obj2FormData() 函数。方括号似乎有效。

function obj2FormData(obj, formData = new FormData()){

    this.formData = formData;

    this.createFormData = function(obj, subKeyStr = ''){
        for(let i in obj){
            let value          = obj[i];
            let subKeyStrTrans = subKeyStr ? subKeyStr + '[' + i + ']' : i;

            if(typeof(value) === 'string' || typeof(value) === 'number'){

                this.formData.append(subKeyStrTrans, value);

            } else if(typeof(value) === 'object'){

                this.createFormData(value, subKeyStrTrans);

            }
        }
    }

    this.createFormData(obj);

    return this.formData;
}

在使用 Ajax 发送数据时,我们将嵌套对象转换为 FormData 对象。

let formData = obj2FormData({
    name : 'Emrah',
    surname : 'Tuncel',
    birth: 1983,
    child : {
        name: 'Eylul',
        surname: 'Tuncel',
        toys: ['ball', 'baby']
    },
    color: ['red', 'yellow']
});

现在让我们发送我们使用 ajax 转换的 FormData。

const xhr = new XMLHttpRequest();
xhr.addEventListener('load', response => {
    //AJAX RESPONSE >>

    console.log(response);

    //AJAX RESPONSE //
});
xhr.open('POST','response.php');
xhr.send(formData);

当我用 PHP 将数据按到屏幕上时,我得到了我想要的确切结果。方法是 POST 还是 GET 都没有关系。

response.php

<pre><? print_r($_GET) ?></pre>
<pre><? print_r($_POST) ?></pre>

输出如下。

Array
(
    [name] => Emrah
    [surname] => Tuncel
    [birth] => 1983
    [child] => Array
        (
            [name] => Eylul
            [surname] => Tuncel
            [toys] => Array
                (
                    [0] => ball
                    [1] => baby
                )

        )

    [color] => Array
        (
            [0] => red
            [1] => yellow
        )

)

希望它有利于您的业务。

【讨论】:

    【解决方案2】:

    使用 hashName[keyName]

    let formData = new FormData();
    let data = {
      title: 'title',
      text: 'text',
      preview: {p_title:'p title', p_text: 'p text'}
    };
    
    for(let key in data) {
      if(typeof(data[key]) === 'object') {
        for (let subKey in data[key]) {
          formData.append('${key}[${subKey}]', data[key][subKey]);
        }
      }
      else {
        formData.append(key, data[key]);
      }
    }
    

    【讨论】:

      【解决方案3】:

      您不需要使用任何第三方模块,如果您有嵌套对象,JSON.stringify() 并不理想。相反,您可以使用Object.entries()。

      // If this is the object you want to convert to FormData...
      const item = {
          description: 'First item',
          price: 13,
          photo: File
      };
      
      const formData = new FormData();
      
      Object.entries(item).forEach(([key, value]) => {
          formData.append(key, value);
      });
      
      // At this point, you can then pass formData to your handler method
      

      在此处阅读有关Object.entries() 的更多信息 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

      【讨论】:

      • 是的,不错。这怎么没有票?
      • @ThaJay 可能是因为它不适用于问题标题所询问的实际嵌套对象。这仅适用于简单的平面对象。
      • @Svish 你是完全正确的。它应该是一个递归函数,如果值是对象或数组,回调应该调用它的父级更深一层。
      • @ThaJay 这还不够,因为FormData 键会一团糟,除非你用它们做点聪明的事。
      • @ThaJay 不知道“jQuery 的默认请求数据编码”是什么样的,但肯定有办法以一种可以解码回对象和数组的方式递归编码 FormData 键值对在后端。例如,object-to-formdata 对密钥进行编码的方式如果发布到 PHP 脚本中应该几乎可以开箱即用。
      【解决方案4】:

      这为我做的工作:

      使用.分隔键和子键

      let formData = new FormData();
      let data = {
        title: 'title',
        text: 'text',
        preview: {p_title:'p title', p_text: 'p text'}
      };
      
      for(let key in data) {
        if(typeof(data[key]) === 'object') {
          for (let subKey in data[key]) {
            formData.append(`${key}.${subKey}`, data[key][subKey]);
          }
        }
        else {
          formData.append(key, data[key]);
        }
      }
      

      【讨论】:

        【解决方案5】:

        要将对象附加到formData,您需要先将其字符串化,如下所示:

        let objToAppend= {
          key1: value1,
          key2: value2,
        }
        let formData = new FormData();
        formData.append('obj', JSON.stringify(objToAppend));
        

        然后在服务器端访问它,你需要先使用JSON.parse() 解析它。 希望对您有所帮助!

        【讨论】:

        • 是FormData,你写的是FormDate
        • @ustaad 嘿,感谢您的提醒。我已经更新了。
        • 仅在服务器需要 json 时有效
        【解决方案6】:

        试试object-to-formdata。这是一个方便的 JavaScript 函数,可以将 Objects 转换为 FormData 实例。

        import { objectToFormData } from 'object-to-formdata';
        
        const object = {
          /**
           * key-value mapping
           * values can be primitives or objects
           */
        };
        
        const options = {
          /**
           * include array indices in FormData keys
           * defaults to false
           */
          indices: false,
        
          /**
           * treat null values like undefined values and ignore them
           * defaults to false
           */
          nullsAsUndefineds: false,
        
          /**
           * convert true or false to 1 or 0 respectively
           * defaults to false
           */
          booleansAsIntegers: false,
        };
        
        const formData = objectToFormData(
          object,
          options, // optional
          existingFormData, // optional
          keyPrefix, // optional
        );
        
        console.log(formData);

        【讨论】:

        • 乍一看这看起来很甜蜜
        【解决方案7】:
        let formData = new FormData();
        let data = {
          title: 'title',
          text: 'text',
          preview: {p_title:'p title', p_text: 'p text'}
        };
        
        for(let dataKey in data) {
          if(dataKey === 'preview') {
            // append nested object
            for (let previewKey in data[dataKey]) {
              formData.append(`preview[${previewKey}]`, data[dataKey][previewKey]);
            }
          }
          else {
            formData.append(dataKey, data[dataKey]);
          }
        }
        

        控制台表单数据

        for (let val of formData.entries()) {
          console.log(val[0]+ ', ' + val[1]); 
        }
        

        【讨论】:

        • 将文件作为值 JSON.stringify 对我不起作用,但确实如此。
        • 这是一个很好的答案!而且,也比从客户端解析 JSON 更安全!
        【解决方案8】:

        这是一个“一个方便的将对象转换为 FormData 实例的 JavaScript 函数”github,也可以作为 npm package 提供,使用非常简单

        let data = {
            title: 'title',
            text: 'text',
            preview: {p_title:'p title', p_text: 'p text'}
        };
        
        var formData = objectToFormData(data);
        

        【讨论】:

          【解决方案9】:

          FormData 值会自动转换为 string。您可以尝试使用Blob 进行操作。

          或者只是使用JSON.stringify(obj)将其作为字符串。

          $.each(data, function(key, value){
              if (typeof(value) === 'object') {
                  value = new Blob([JSON.stringify(value)], {type : 'application/json'});// or just JSON.stringify(value)
              }
              formData.append(key, value);
          });
          

          【讨论】:

          • 添加了 sn-p @ShibinRagh
          • 为什么要将它转换为 Blob?只需将 JSON 作为字符串发送,因为它不是二进制数据,所以将它作为多部分二进制发送不会赢得任何东西。
          猜你喜欢
          • 2022-08-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-03
          • 1970-01-01
          • 2018-07-16
          • 1970-01-01
          相关资源
          最近更新 更多