如何正确使用axios参数与数组

121

如何在查询字符串中为数组添加索引?

我尝试发送以下数据:

axios.get('/myController/myAction', { params: { storeIds: [1,2,3] })

我得到了这个网址:

http://localhost/api/myController/myAction?storeIds[]=1&storeIds[]=2&storeIds[]=3

所以,我应该获得这个URL:

http://localhost/api/myController/myAction?storeIds[0]=1&storeIds[1]=2&storeIds[2]=3

我应该在我的params选项中添加什么才能获得这个URL?


只是出于好奇 - 带有 [] 的 URL 仍然有效吗? - Julix
18个回答

160

您可以使用paramsSerializer,并使用https://www.npmjs.com/package/qs序列化参数。

axios.get('/myController/myAction', {
  params: {
    storeIds: [1,2,3]
  },
  paramsSerializer: params => {
    return qs.stringify(params)
  }
})

2
帮了很多忙...之前一直卡在自己如何构建参数上。 - dvlden
4
连axios的文档中也只是“顺带一提”地提到了paramsSerializer。 - smith64fx
1
请注意,通过这样做,“params”变成了“query”。因此,在后端访问它时,您必须编写req.query而不是req.params。 至少对我来说是这样。 - Jakub A Suplicki
23
我使用了qs.stringify(params, { arrayFormat: "repeat" })而不仅仅是qs.stringify(params)才让它起作用。这个答案也很有帮助:https://dev59.com/mVgQ5IYBdhLWcg3wWCrP#46153494 - Sam
4
自1.0.0版本以来,axios已原生支持此功能,只需将paramsSerializer.indexes设置为null即可。 参考:https://github.com/axios/axios#request-config - Gabriel Hobold
显示剩余3条评论

26

不需要添加更多的库,使用ES6即可编写:

axios.get(`/myController/myAction?${[1,2,3].map((n, index) => `storeIds[${index}]=${n}`).join('&')}`);

2
FYI,Axios 是一个库。https://github.com/axios/axios - user1853517
1
哎呀!我是说更多的库。我已经更正了答案,谢谢! - Sergio Loaiza
2
我喜欢这个答案!它是纯JS编写的,不需要任何库! - michael_vons
2
为了使它工作,我做了以下更改:.map((n, index) => storeIds[${index}]=${n}).join('&')否则,由于.map返回一个数组,我必须执行join操作。否则将在每个值之间获得不需要的“,”符号。 - Per Hyyrynen
@PerHyyrynen 你说得对!我会纠正答案,谢谢! - Sergio Loaiza

16

非常感谢 Nicu Criste 的答案。对于我的情况,API需要这样的参数:

params: {
  f: {
    key: 'abc',
    categories: ['a','b','c']
   },
  per_page: 10
}

方法是GET,这个API需要的格式是: API?f[key]=abc&f[categories][]=a&f[categories][]=b... 所以我像这样分配了axios的paramsSerializer:

config.paramsSerializer = p => {
      return qs.stringify(p, {arrayFormat: 'brackets'})
    }

12

这种行为已经在版本1.0.0中添加到axios中。请参见https://github.com/axios/axios/tree/v1.0.0#request-configparamsSerializer.indexes

以下是使用您的示例代码的示例:

axios.get('/myController/myAction', {
  params: { storeIds: [1,2,3] },
  paramsSerializer: {
    indexes: true, // use brackets with indexes
  }
)

生成的查询参数将在方括号内具有索引:
/myController/myAction?storeIds[0]=1&storeIds[1]=2&storeIds[2]=3

其他paramsSerializer.indexes的值为null(没有括号):
axios.get('/myController/myAction', {
  params: { storeIds: [1,2,3] },
  paramsSerializer: {
    indexes: null, // no brackets at all
  }
)
// /myController/myAction?storeIds=1&storeIds=2&storeIds=3

默认设置为false(括号内没有索引):
axios.get('/myController/myAction', {
  params: { storeIds: [1,2,3] },
  paramsSerializer: {
    indexes: false, // brackets but no indexes
  }
)
// /myController/myAction?storeIds[]=1&storeIds[]=2&storeIds[]=3

4

在我的情况下,我使用ES6数组函数。使用reduce函数生成查询字符串的数组元素。对象数组也适用。

const storeIds = [1,2,3]
axios.get('some url', {
  params: {
    storeIds: storeIds.reduce((f, s) => `${f},${s}`)
  }
})

11
您的解决方案可以稍微简短一些,写成storeIds.join(',') - Justin

2

这里有很多好的答案。但我只想分享我最终使用的内容:(即使在对象中有其他非数组参数,也可以完美运行)

这是我的params对象:

params: {
    city: '335471',
    size: 4,
    page: 1,
    type: [1, 2, 3, 4, 5, 6],
}

这是 axios 的 get 方法:

$axios.get('/some/api/endpoint/', {
    params,
    paramsSerializer: (params) => parseParams(params),
})

function parseParams(params) {
  const keys = Object.keys(params)
  let options = ''

  keys.forEach((key) => {
    const isParamTypeObject = typeof params[key] === 'object'
    const isParamTypeArray = isParamTypeObject && params[key].length >= 0

    if (!isParamTypeObject) {
      options += `${key}=${params[key]}&`
    }

    if (isParamTypeObject && isParamTypeArray) {
      params[key].forEach((element) => {
        options += `${key}=${element}&`
      })
    }
  })

  return options ? options.slice(0, -1) : options
}

最后,使用这种方法,您将发送此请求:

https://yourwebsite.com/api/some/api/endpoint/?city=335471&size=4&page=1&type=1&type=2&type=3&type=4&type=5&type=6

来源:https://github.com/axios/axios/issues/604#issuecomment-420135579


1
这个答案是由@Nicu Criste的答案启发而来的。
但可能与发布的问题无关。
以下代码用于生成带有重复键的查询参数,这些参数已经由对象数组提供。
注意:如果您是bundlephobia的开发人员,请谨慎使用以下方法:因为UrlSearchParams在不同的浏览器和平台上支持程度不同
const queryParams = [{key1: "value1"}, {key2: "value2"}]

axios.get('/myController/myAction', {
  params: queryParams,
  paramsSerializer: params => {
    return params.map((keyValuePair) => new URLSearchParams(keyValuePair)).join("&")
  }
})

// request -> /myController/myAction?key1=value1&key2=value2

1
你可以创建一个名为parseParams的函数,该函数可以将参数发送到此函数并对其进行序列化。

axios.get('/myController/myAction', {
  params: {
    storeIds: [1,2,3]
  },
 paramsSerializer: params => parseParams(params)
})

parseParams 函数是:

export const parseParams = (params) => {
  let options = '';

  for (const [key, value] of Object.entries(params)) {
    if (Array.isArray(value)) {
      for (const element of value) {
        options += `${key}=${element}&`;
      }
    } else {
      options += `${key}=${value}&`;
    }
  }

  return options.slice(0, -1);
};


1
在我的情况下,我正在使用类似这样的东西。
const params = array.map((v)=>{
            return `p=${v}&`
        })

只需将params.join('')与获取数据的URL连接起来:

`url_to_get?${params.join('')`

在我的 ASP.net 后端收到以下内容:
[FromUri] string [] p

1

我重写了axios中现有的paramSerializer。下面的代码片段在将方括号之间的索引放置时执行相同的序列化操作。我尝试过qs,但它与我的Python Connexion后端(用于JSON字符串参数)不兼容。

const rcg = axios.create({
    baseURL: `${url}/api`,
    paramsSerializer: params => {
        const parts = [];

        const encode = val => {
            return encodeURIComponent(val).replace(/%3A/gi, ':')
                .replace(/%24/g, '$')
                .replace(/%2C/gi, ',')
                .replace(/%20/g, '+')
                .replace(/%5B/gi, '[')
                .replace(/%5D/gi, ']');
        }

        const convertPart = (key, val) => {
            if (val instanceof Date)
                val = val.toISOString()
            else if (val instanceof Object)
                val = JSON.stringify(val)

            parts.push(encode(key) + '=' + encode(val));
        }

        Object.entries(params).forEach(([key, val]) => {
            if (val === null || typeof val === 'undefined')
                return

            if (Array.isArray(val))
                val.forEach((v, i) => convertPart(`${key}[${i}]`, v))
            else
                convertPart(key, val)
        })

        return parts.join('&')
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接