【问题标题】:appending array to FormData and send via AJAX将数组附加到 FormData 并通过 AJAX 发送
【发布时间】:2013-04-12 19:33:26
【问题描述】:

我正在使用 ajax 提交包含数组、文本字段和文件的多部分表单。

我将每个 VAR 附加到主数据中

var attachments = document.getElementById('files'); 
var data= new FormData();

for (i=0; i< attachments.files.length; i++){
    data.append('file', attachments.files[i]);
    console.log(attachments.files[i]);

    data.append ('headline', headline);
    data.append ('article', article);
    data.append ('arr', arr);
    data.append ('tag', tag);

然后我使用 ajax 函数将其发送到 PHP 文件以存储在 sql DB 中。

$.ajax({    
    type: "post",
    url: 'php/submittionform.php',
    cache: false,
    processData: false,
    contentType: false,
    data: data,
    success: function(request) {$('#box').html(request); }
})

但是在 PHP 端,arr 变量,它是一个数组,显示为一个字符串。

当我不使用 ajax 作为表单数据发送它,而是使用简单的$.POST 选项时,我确实将它作为 PHP 端的一个数组,但我也无法发送文件。

有什么解决办法吗?

【问题讨论】:

    标签: javascript ajax arrays form-data


    【解决方案1】:

    您也可以通过这种方式通过FormData 发送数组:

    var formData = new FormData;
    var arr = ['this', 'is', 'an', 'array'];
    for (var i = 0; i < arr.length; i++) {
        formData.append('arr[]', arr[i]);
    }
    

    因此,您可以像使用简单的 HTML 表单一样编写 arr[]。如果是 PHP,它应该可以工作。

    您可能会发现这篇文章很有用:How to pass an array within a query string?

    【讨论】:

    • @Oleg 在formData.append('arr[]', arr[i]); 中写arr[] 有什么必要?为什么arr 不正确?我都试过了,但只有 arr[] 有效。
    • @Totoro 因为在arr 的情况下,您只需在每次循环迭代时重新定义此值,最后,最终值将等于最后一个数组元素,而不是整个数组
    • @Oleg 如果重新定义是这种情况,那么 arr[] 有什么不同,为什么 arr[] 没有重新定义? arr[] 也是一个字符串。在我的情况下,在测试 arrarr[] 时都没有重新定义。我在 FormData 中得到了多个数组,它们具有相同的键但不同的值。所以我得到了arr,其值为1,另一个arr,其值为2
    • @Totoro 是的,你是对的,我的错误。我相信这是更多特定于服务器端的问题。不同的语言可能会以不同的方式解析查询字符串。例如,PHP 的行为与您描述的一样,但我看到了示例(如果内存服务,在 Java 中),其中arr 也适用于数组。在this topic 有这个问题的更详细的答案
    • 如果有人想发布一组对象,您可以将此答案扩展为如下for (var i = 0; i &lt; myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
    【解决方案2】:

    您有多种选择:

    将其转换为 JSON 字符串,然后在 PHP 中解析(推荐)

    JS

    var json_arr = JSON.stringify(arr);
    

    PHP

    $arr = json_decode($_POST['arr']);
    

    或者使用@Curios's method

    通过FormData发送数组。


    不推荐:用序列化数据,然后用 PHP 反序列化

    JS

    // Use <#> or any other delimiter you want
    var serial_arr = arr.join("<#>"); 
    

    PHP

    $arr = explode("<#>", $_POST['arr']);
    

    【讨论】:

    • 问题是数组包含真实文本行,带有空格和标点符号。我不想搞砸了。
    • 当您使用 JSON 对其进行编码和解析时,数据不会丢失。试一试;)
    • 如果您正在使用带有自动映射或类似功能的 asp.net,那么您需要的是 @Curious 答案。
    • @Richard de Wit 如果你有 File 或 FormData 这样的数据,你会在 json.stringfy 中丢失它们
    • 我更喜欢字符串化,更简单。因为您需要进行某种递归以使用 [] 传递数组数组,但很高兴知道可以这样做。
    【解决方案3】:

    打字稿版本:

    export class Utility {      
        public static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
            let formData = form || new FormData();
            let formKey;
    
            for (let propertyName in model) {
                if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
                let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
                if (model[propertyName] instanceof Date)
                    formData.append(formKey, model[propertyName].toISOString());
                else if (model[propertyName] instanceof Array) {
                    model[propertyName].forEach((element, index) => {
                        const tempFormKey = `${formKey}[${index}]`;
                        this.convertModelToFormData(element, formData, tempFormKey);
                    });
                }
                else if (typeof model[propertyName] === 'object' && !(model[propertyName] instanceof File))
                    this.convertModelToFormData(model[propertyName], formData, formKey);
                else
                    formData.append(formKey, model[propertyName].toString());
            }
            return formData;
        }
    }
    

    使用:

    let formData = Utility.convertModelToFormData(model);
    

    【讨论】:

    • 非常感谢,它工作正常!对于那些不使用 Typescript 的人,您只需删除第一行和最后一行 + 将方法声明 public static 替换为 function + 删除类型声明 : any: FormData: FormData
    • 到目前为止,该函数会跳过零和空字符串。要包含它们,请将第 7 行的 if 块替换为:if (!model.hasOwnProperty(propertyName) || (!model[propertyName] &amp;&amp; model[propertyName]!==0 &amp;&amp; model[propertyName]!=='')) continue;
    【解决方案4】:

    这是一个老问题,但我最近在发布对象和文件时遇到了这个问题。我需要能够发布一个对象,其子属性也是对象和数组。

    下面的函数将遍历一个对象并创建正确的 formData 对象。

    // formData - instance of FormData object
    // data - object to post
    function getFormData(formData, data, previousKey) {
      if (data instanceof Object) {
        Object.keys(data).forEach(key => {
          const value = data[key];
          if (value instanceof Object && !Array.isArray(value)) {
            return this.getFormData(formData, value, key);
          }
          if (previousKey) {
            key = `${previousKey}[${key}]`;
          }
          if (Array.isArray(value)) {
            value.forEach(val => {
              formData.append(`${key}[]`, val);
            });
          } else {
            formData.append(key, value);
          }
        });
      }
    }
    

    这将转换以下 json -

    {
      name: 'starwars',
      year: 1977,
      characters: {
        good: ['luke', 'leia'],
        bad: ['vader'],
      },
    }
    

    进入下面的FormData

     name, starwars
     year, 1977
     characters[good][], luke
     characters[good][], leia
     characters[bad][], vader
    

    【讨论】:

    • 这对我很有用,只需要在附加内的值上应用字符串(值)(否则它会因真/假而失败)。它也应该是(value !== null) &amp;&amp; formData.append(key, value) 而不仅仅是formData.append(key, value) 否则它会在空值上失败
    【解决方案5】:

    将所有类型输入添加到 FormData

    const formData = new FormData();
    for (let key in form) {
        Array.isArray(form[key])
            ? form[key].forEach(value => formData.append(key + '[]', value))
            : formData.append(key, form[key]) ;
    }
    

    【讨论】:

      【解决方案6】:

      这是convertModelToFormData 的另一个版本,因为我需要它也能够发送文件。

      utility.js

      const Utility = {
        convertModelToFormData(val, formData = new FormData, namespace = '') {
          if ((typeof val !== 'undefined') && val !== null) {
            if (val instanceof Date) {
              formData.append(namespace, val.toISOString());
            } else if (val instanceof Array) {
              for (let i = 0; i < val.length; i++) {
                this.convertModelToFormData(val[i], formData, namespace + '[' + i + ']');
              }
            } else if (typeof val === 'object' && !(val instanceof File)) {
              for (let propertyName in val) {
                if (val.hasOwnProperty(propertyName)) {
                  this.convertModelToFormData(val[propertyName], formData, namespace ? `${namespace}[${propertyName}]` : propertyName);
                }
              }
            } else if (val instanceof File) {
              formData.append(namespace, val);
            } else {
              formData.append(namespace, val.toString());
            }
          }
          return formData;
        }
      }
      export default Utility;
      
      

      我的客户端代码.js

      import Utility from './utility'
      ...
      someFunction(form_object) {
        ...
        let formData = Utility.convertModelToFormData(form_object);
        ...
      }
      

      【讨论】:

        【解决方案7】:

        下一个版本适用于包含一系列简单值的模型:

        function convertModelToFormData(val, formData = new FormData(), namespace = '') {
            if((typeof val !== 'undefined') && (val !== null)) {
                if(val instanceof Date) {
                    formData.append(namespace, val.toISOString());
                } else if(val instanceof Array) {
                    for(let element of val) {
                        convertModelToFormData(element, formData, namespace + '[]');
                    }
                } else if(typeof val === 'object' && !(val instanceof File)) {
                    for (let propertyName in val) {
                        if(val.hasOwnProperty(propertyName)) {
                            convertModelToFormData(val[propertyName], formData, namespace ? namespace + '[' + propertyName + ']' : propertyName);
                        }
                    }
                } else {
                    formData.append(namespace, val.toString());
                }
            }
            return formData;
        }
        

        【讨论】:

          【解决方案8】:

          如果您有嵌套对象和数组,填充 FormData 对象的最佳方法是使用递归。

          function createFormData(formData, data, key) {
              if ( ( typeof data === 'object' && data !== null ) || Array.isArray(data) ) {
                  for ( let i in data ) {
                      if ( ( typeof data[i] === 'object' && data[i] !== null ) || Array.isArray(data[i]) ) {
                          createFormData(formData, data[i], key + '[' + i + ']');
                      } else {
                          formData.append(key + '[' + i + ']', data[i]);
                      }
                  }
              } else {
                  formData.append(key, data);
              }
          }
          

          【讨论】:

            【解决方案9】:

            基于@YackY 回答更短的递归版本:

            function createFormData(formData, key, data) {
                if (data === Object(data) || Array.isArray(data)) {
                    for (var i in data) {
                        createFormData(formData, key + '[' + i + ']', data[i]);
                    }
                } else {
                    formData.append(key, data);
                }
            }
            

            使用示例:

            var data = {a: '1', b: 2, c: {d: '3'}};
            var formData = new FormData();
            createFormData(formData, 'data', data);
            

            发送数据:

            data[a]=1&
            data[b]=2&
            data[c][d]=3
            

            【讨论】:

              【解决方案10】:

              我已经修复了打字稿版本。对于 javascript,只需删除类型定义。

                _getFormDataKey(key0: any, key1: any): string {
                  return !key0 ? key1 : `${key0}[${key1}]`;
                }
                _convertModelToFormData(model: any, key: string, frmData?: FormData): FormData {
                  let formData = frmData || new FormData();
              
                  if (!model) return formData;
              
                  if (model instanceof Date) {
                    formData.append(key, model.toISOString());
                  } else if (model instanceof Array) {
                    model.forEach((element: any, i: number) => {
                      this._convertModelToFormData(element, this._getFormDataKey(key, i), formData);
                    });
                  } else if (typeof model === 'object' && !(model instanceof File)) {
                    for (let propertyName in model) {
                      if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
                      this._convertModelToFormData(model[propertyName], this._getFormDataKey(key, propertyName), formData);
                    }
                  } else {
                    formData.append(key, model);
                  }
              
                  return formData;
                }
              

              【讨论】:

                【解决方案11】:

                将三种格式的Data转化为FormData

                1.单个值,如字符串、数字或布尔值

                 let sampleData = {
                  activityName: "Hunting3",
                  activityTypeID: 2,
                  seasonAssociated: true, 
                };
                

                2。数组是对象数组

                let sampleData = {
                   activitySeason: [
                    { clientId: 2000, seasonId: 57 },
                    { clientId: 2000, seasonId: 57 },
                  ],
                };
                

                3.持有键值对的对象

                let sampleData = {
                    preview: { title: "Amazing World", description: "Here is description" },
                };
                

                让我们的生活变得轻松的东西:

                function transformInToFormObject(data) {
                  let formData = new FormData();
                  for (let key in data) {
                    if (Array.isArray(data[key])) {
                      data[key].forEach((obj, index) => {
                        let keyList = Object.keys(obj);
                        keyList.forEach((keyItem) => {
                          let keyName = [key, "[", index, "]", ".", keyItem].join("");
                          formData.append(keyName, obj[keyItem]);
                        });
                      });
                    } else if (typeof data[key] === "object") { 
                      for (let innerKey in data[key]) {
                        formData.append(`${key}.${innerKey}`, data[key][innerKey]);
                      }
                    } else {
                      formData.append(key, data[key]);
                    }
                  }
                  return formData;
                }
                

                示例: 输入数据

                let sampleData = {
                  activityName: "Hunting3",
                  activityTypeID: 2,
                  seasonAssociated: true,
                  activitySeason: [
                    { clientId: 2000, seasonId: 57 },
                    { clientId: 2000, seasonId: 57 },
                  ],
                  preview: { title: "Amazing World", description: "Here is description" },
                };
                

                输出表单数据:

                activityName: Hunting3
                activityTypeID: 2
                seasonAssociated: true
                activitySeason[0].clientId: 2000
                activitySeason[0].seasonId: 57
                activitySeason[1].clientId: 2000
                activitySeason[1].seasonId: 57
                preview.title: Amazing World
                preview.description: Here is description
                

                【讨论】:

                  【解决方案12】:

                  JavaScript 代码:

                  var formData = new FormData();
                  let arr = [1,2,3,4];
                  formData.append('arr', arr);
                  

                  在 php 上的输出:

                  $arr = $_POST['arr']; ===>  '1,2,3,4'
                  

                  解决php代码:

                  $arr = explode(",", $_POST['arr']); ===> [1,2,3,4]
                  

                  【讨论】:

                  • 这可以使用一些解释说明它为什么以及如何工作,而不是仅仅显示你认为有效的代码。
                  • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
                  猜你喜欢
                  • 2021-01-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-08-04
                  • 2014-10-01
                  • 2023-03-03
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多