使用 fetch 发送带有数据 object 的获取请求

Use fetch to send get request with data object

我在项目中使用 Fetch (Fetch API),为了保持一致性,我想创建一个函数来接收所有参数,例如方法、url 和数据以及创建正确的请求,具体取决于它是 GET 还是 POST 请求。

是否可以使用 Fetch 发送数据 object,对于 GET 请求,将数据转换为带参数的字符串,如果是 POST 请求,则只发送body?

中的数据 object

看起来像这样:

fetch ('/test', {
        method: 'GET',
        data: {
           test: 'test'
        }
});

这个疑问是受这个jQueryajax行为的启发:

$.ajax({
   url: '/test',
   method: 'GET',
   data: {
      test: 'test'
   }
});

这会产生这个请求:

'/test/?test=test'

If I pass the data object as normal in the fetch constructor for a GET request, would it send the request like the example I gave '/test/?test=test'

如果要将查询字符串添加到提取请求:

From the SPEC

var url = new URL("https://a.com/method"),
params = {a:1, b:2}
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
fetch(url)

这将产生一个请求:

您可以使用 Url class:

var url = new URL("/test/")
Object.keys({test: 'test', a: 1}).forEach(key => url.searchParams.append(key, params[key]))
fetch(url);

或者自己解析字符串,如果你想要更广泛的浏览器支持:

var params = {test: 'test', a: 1},
    qs = Object.keys(params).reduce(function(_qs, k, i){ return _qs + '&' + k + '=' + params[k]; }, '').substring(1);

console.log(qs)

我将向您展示使用和不使用 URLSearchParams 创建查询的片段。

代码将在 typescript 中供您使用。如果不是,只需删除类型,它将以相同的方式工作。

简单的解决方案(URLSearchParams):

/**
 * Creates query from given object
 * - It doesn't work with deep nesting
 * - It doesn't remove empty fields
 * @returns `state1=6&state2=horse` without `?`
 */
function createQuery(queryObject?: Record<string | number, unknown> | null): string {
  if (queryObject == null) return ""
  // Typescript: The `as ...` expression here is ok because `URLSearchParams` will convert non-string by itself
  const searchParams = new URLSearchParams(queryObject as Record<string, string>)
  return searchParams.toString()
}

解决问题解决方案(URLSearchParams)

/**
 * Creates query from given object
 * - It doesn't work with deep nesting
 * - Removes empty fields
 * @returns `state1=6&state2=horse` without `?`
 */
function createQuery(queryObject?: Record<string | number, unknown> | null): string {
  if (queryObject == null || !Object.keys(queryObject).length) return ""
  for (const key in queryObject) {
    if (Object.prototype.hasOwnProperty.call(queryObject, key)) {
      const value = queryObject[key]
      // Use `!value` expression if you want to delete values as `0` (zero) and `""` (empty string) too.
      if (value == null) delete queryObject[key]
    }
  }
  const searchParams = new URLSearchParams(queryObject as Record<string, string>)
  return searchParams.toString()
}

无 URLSearchParams 解决方案:

/**
 * Creates query from given object
 * - Supports prefixes
 * - Supports deep nesting
 * - Removes empty fields
 * @returns `state1=6&state2=horse` without `?`
 */
function createQuery(queryObject?: Record<string | number, unknown> | null, keyPrefix?: string): string {
  if (queryObject == null || !Object.keys(queryObject).length) return ""
  keyPrefix = keyPrefix ? (keyPrefix + "_") : ""

  const queryKeys = Object.keys(queryObject)
  const queryArray = queryKeys.map(key => {
    const value = queryObject[key]
    if (value) {
      if (isDictionary(value)) {
        return createQuery(value, keyPrefix + key + "_")
      }

      return keyPrefix + encodeURIComponent(key) + "=" + encodeURIComponent(String(value))
    }
    return ""
  })

  return queryArray.filter(Boolean).join("&")
}

IsDictionary 助手:

我这里也用了isDictionaryhelper,你可以找到here

用法

你需要在端点的开头加上 ? 加上 createQuery

fetch("/test?" + createQuery({ foo: 12, bar: "@user->here", object: { test: "test", bird: { super: { ultra: { mega: { deep: "human" }, shop: 7 } }, multiple: [1, 2, 3] } } }))

结果

foo=12&bar=%40user-%3Ehere&object_test=test&object_bird_super_ultra_mega_deep=human&object_bird_super_ultra_shop=7&object_bird_multiple=1%2C2%2C3

foo: 12
bar: @user->here
object_test: test
object_bird_super_ultra_mega_deep: human
object_bird_super_ultra_shop: 7
object_bird_multiple: 1,2,3

结论

您可以根据自己的目标选择不同的片段。