【问题标题】:Setting query string using Fetch GET request使用 Fetch GET 请求设置查询字符串
【发布时间】:2016-05-04 11:49:39
【问题描述】:

我正在尝试使用新的Fetch API

我正在发出这样的GET 请求:

var request = new Request({
  url: 'http://myapi.com/orders',
  method: 'GET'
});
fetch(request);

但是,我不确定如何将查询字符串添加到 GET 请求。理想情况下,我希望能够向URL 发出GET 请求,例如:

'http://myapi.com/orders?order_id=1'

jQuery 中,我可以通过将{order_id: 1} 作为$.ajax()data 参数传递来做到这一点。新的Fetch API 有没有等效的方法?

【问题讨论】:

    标签: javascript jquery http fetch-api


    【解决方案1】:

    2017 年 3 月更新:

    URL.searchParams 支持已正式登陆 Chrome 51,但其他浏览器仍需要polyfill


    官方使用查询参数的方式只是将它们添加到 URL 中。来自the spec,这是一个例子:

    var url = new URL("https://geo.example.org/api"),
        params = {lat:35.696233, long:139.570431}
    Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
    fetch(url).then(/* … */)
    

    但是,我不确定 Chrome 是否支持 URL 的 searchParams 属性(在撰写本文时),因此您可能希望使用 third party libraryroll-your-own solution

    2018 年 4 月更新:

    使用URLSearchParams constructor,您可以分配一个二维数组或一个对象,然后将其分配给url.search,而不是遍历所有键并附加它们

    var url = new URL('https://sl.se')
    
    var params = {lat:35.696233, long:139.570431} // or:
    var params = [['lat', '35.696233'], ['long', '139.570431']]
    
    url.search = new URLSearchParams(params).toString();
    
    fetch(url)
    

    旁注:URLSearchParams 在 NodeJS 中也可用

    const { URL, URLSearchParams } = require('url');
    

    【讨论】:

    • 还有developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/…,尽管在撰写本文时它仍在通过规范,但还没有得到很好的支持。而且 API 更像 Java 而不是 JS。 ://
    • 请参阅caniuse.com/#feat=urlsearchparams 以获得对URLSearchParams 接口的支持;我会假设(尽管我不是 100% 确定)红色的浏览器正是URL 对象不具有.searchParams 属性的浏览器。重要的是,Edge 仍然没有支持。
    • 来自文档:“请注意,不推荐使用 URLSearchParams 实例;很快浏览器将只使用 USVString 进行初始化。”来源:developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/…
    • new URLSearchParams 似乎无法与 Array 属性一起正常工作。我希望它将属性array: [1, 2] 转换为array[]=1&array[]=2,但将其转换为array=1,2。手动使用它的append 方法确实会导致array=1&array=2,但我必须遍历 params 对象,并且只对数组类型这样做,不是很符合人体工程学。
    • 确实是加错了:) github.com/mdn/sprints/issues/2856
    【解决方案2】:

    正如已经回答的那样,这对于 fetch-API 来说是不可能的。但我必须注意:

    如果您使用node,则有querystring 包。它可以字符串化/解析对象/查询字符串:

    var querystring = require('querystring')
    var data = { key: 'value' }
    querystring.stringify(data) // => 'key=value'
    

    ...然后将其附加到要请求的 url。


    但是,上面的问题是,您总是必须在前面加上一个问号 (?)。因此,另一种方法是使用节点url 包中的parse 方法,并按如下方式执行:

    var url = require('url')
    var data = { key: 'value' }
    url.format({ query: data }) // => '?key=value'
    

    queryhttps://nodejs.org/api/url.html#url_url_format_urlobj

    这是可能的,因为它在内部只是this

    search = obj.search || (
        obj.query && ('?' + (
            typeof(obj.query) === 'object' ?
            querystring.stringify(obj.query) :
            String(obj.query)
        ))
    ) || ''
    

    【讨论】:

      【解决方案3】:
      let params = {
        "param1": "value1",
        "param2": "value2"
      };
      
      let query = Object.keys(params)
                   .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
                   .join('&');
      
      let url = 'https://example.com/search?' + query;
      
      fetch(url)
        .then(data => data.text())
        .then((text) => {
          console.log('request succeeded with JSON response', text)
        }).catch(function (error) {
          console.log('request failed', error)
        });
      

      【讨论】:

      • 您需要对密钥进行编码吗?我从来没有这样做过。
      • @chovy - 如果您的密钥包含特殊字符,例如“&”,您会这样做。大多数时候不会,但有时可以。
      • 注意:encodeURIComponent 可能会产生不好的结果,例如它会错误地将空格编码为“%20”而不是“+” - 当您进行百分比编码时,这种行为很好,例如,URL 的路径(预期的用例),但查询参数通常是表单编码的,它遵循旧版本的百分比编码规范 - 您可以使用 URLSearchParams() 正确编码/解码查询参数。请参阅this S.O. question 了解更多信息。
      【解决方案4】:

      也许这样更好:

      const withQuery = require('with-query');
      
      fetch(withQuery('https://api.github.com/search/repositories', {
        q: 'query',
        sort: 'stars',
        order: 'asc',
      }))
      .then(res => res.json())
      .then((json) => {
        console.info(json);
      })
      .catch((err) => {
        console.error(err);
      });
      

      【讨论】:

        【解决方案5】:

        我知道这是绝对显而易见的,但我觉得值得添加这个作为答案,因为它是最简单的:

        const orderId = 1;
        fetch('http://myapi.com/orders?order_id=' + orderId);
        

        【讨论】:

        • 值得说明的是,这只适用于整数类型。如果您使用字符串,尤其是用户提供的字符串(如搜索条件),则必须对字符串进行转义,否则如果字符串中出现 /+& 等字符,则会得到奇怪的结果。跨度>
        • 使用 Request 对象会有所帮助,特别是如果您想使用函数来构建请求,然后将其交给 fetch() 调用,但我不认为使用它是“绝对明显的” ”。此外,不应在配置选项的对象文字中指定 url;它应该作为第一个参数单独传递给 Request 构造函数 (developer.mozilla.org/en-US/docs/Web/API/Request/Request)。
        • @Gen1-1, ty.做了一些修改。我的示例基于 OP 的 sn-p,但我对其进行了一些简化。
        【解决方案6】:

        模板文字在这里也是一个有效的选项,并提供一些好处。

        您可以包含原始字符串、数字、布尔值等:

            let request = new Request(`https://example.com/?name=${'Patrick'}&number=${1}`);
        

        您可以包含变量:

            let request = new Request(`https://example.com/?name=${nameParam}`);
        

        您可以包含逻辑和功能:

            let request = new Request(`https://example.com/?name=${nameParam !== undefined ? nameParam : getDefaultName() }`);
        

        就构造较大查询字符串的数据而言,我喜欢使用连接到字符串的数组。我发现它比其他一些方法更容易理解:

        let queryString = [
          `param1=${getParam(1)}`,
          `param2=${getParam(2)}`,
          `param3=${getParam(3)}`,
        ].join('&');
        
        let request = new Request(`https://example.com/?${queryString}`, {
          method: 'GET'
        });
        

        【讨论】:

        • 您必须非常小心这种方法,因为它不会首先对字符串进行 URL 转义。因此,如果您得到一个包含 +& 之类字符的变量,那么它将无法按预期工作,并且您最终会得到与您想象的不同的参数和值。
        【解决方案7】:

        encodeQueryString — 将对象编码为查询字符串参数

        /**
         * Encode an object as url query string parameters
         * - includes the leading "?" prefix
         * - example input — {key: "value", alpha: "beta"}
         * - example output — output "?key=value&alpha=beta"
         * - returns empty string when given an empty object
         */
        function encodeQueryString(params) {
            const keys = Object.keys(params)
            return keys.length
                ? "?" + keys
                    .map(key => encodeURIComponent(key)
                        + "=" + encodeURIComponent(params[key]))
                    .join("&")
                : ""
        }
        
        encodeQueryString({key: "value", alpha: "beta"})
         //> "?key=value&alpha=beta"
        

        【讨论】:

          【解决方案8】:

          你可以从query string使用#stringify

          import { stringify } from 'query-string';
          
          fetch(`https://example.org?${stringify(params)}`)
          

          【讨论】:

            【解决方案9】:

            简洁、现代的方法:

            fetch('https://example.com?' + new URLSearchParams({
                foo: 'value',
                bar: 2,
            }))
            

            URLSearchParams's toString() 函数会将提供的查询参数转换为字符串。在 JavaScript 中,当您将对象与字符串连接时,该对象的 toString() 函数将自动为您调用。您可能希望更明确地了解此处发生的情况,并选择在将两个值连接在一起之前自己调用 .toString() ,如下所示:fetch('https://...' + new URLSearchParams(...).toString())


            IE不支持URLSearchParams(或fetch),但是有polyfillsavailable

            如果使用节点,您可以通过 node-fetch 之类的包添加 fetch API。 URLSearchParams 带有节点,从版本 10 开始可以作为全局对象找到。在旧版本中,您可以在 require('url').URLSearchParams 找到它。

            如果你同时使用 node 和 typescript,你会发现,由于一些技术限制,typescript 不提供全局 URLSearchParams 的类型定义。最简单的解决方法是从 URL 模块导入它。请参阅here 了解更多信息。

            【讨论】:

            • 感谢分享。我认为这应该被接受的答案。被要求将参数传递给 fetch API,虽然这是不可能的,但这个答案非常接近结构上的样子。
            • 这似乎不能正确处理同一个键的多个值。我期待能够写 new URLSearchParams({foo: ['bar', 'baz']}) 但不是 foo=bar&foo=baz 它被转义为 foo=bar%Cbaz
            • @jymbob 要拥有多个值,您必须在 URLSearchParams 上使用 .append() 方法。例如s = new URLSearchParams({foo: 'bar'}); s.append('foo', 'baz'); s.toString()。或者,构造函数可以采用列表列表而不是对象。 new URLSearchParams([['foo', 'bar'], ['foo', 'baz']]).toString()查看文档页面了解更多使用信息:developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
            • @ScottyJamison 感谢您的回复。我从文档中发现了这一点,但是如果我不能传入 dict 并在另一端获取预期的搜索参数,它就会使 URLSearchParams 对我毫无用处。
            • 更简洁的方法是使用字符串插值:``` https://example.com?${new URLSearchParams({foo: 'value'})} ``` developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
            【解决方案10】:

            刚刚使用 Nativescript 的 fetchModule 并使用字符串操作找到了我自己的解决方案。 将查询字符串逐位附加到 url。这是一个将查询作为 json 对象传递的示例 (query = {order_id: 1}):

            function performGetHttpRequest(fetchLink='http://myapi.com/orders', query=null) {
                if(query) {
                    fetchLink += '?';
                    let count = 0;
                    const queryLength = Object.keys(query).length;
                    for(let key in query) {
                        fetchLink += key+'='+query[key];
                        fetchLink += (count < queryLength) ? '&' : '';
                        count++;
                    }
                }
                // link becomes: 'http://myapi.com/orders?order_id=1'
                // Then, use fetch as in MDN and simply pass this fetchLink as the url.
            }
            

            我在多个查询参数上对此进行了测试,它就像一个魅力:) 希望这对某人有所帮助。

            【讨论】:

            • 这是一个很好的例子,说明了为什么您应该使用 3rd 方库 - 您的代码可能运行良好,但有人已经做得更好了
            【解决方案11】:

            var paramsdate=01+'%s'+12+'%s'+2012+'%s';

            request.get("https://www.exampleurl.com?fromDate="+paramsDate;

            【讨论】:

              【解决方案12】:

              无外部包的解决方案

              使用 fetch api 执行 GET 请求,我在这个不需要安装包的解决方案上工作。

              这是调用 google 地图 api 的示例

              // encode to scape spaces
              const esc = encodeURIComponent;
              const url = 'https://maps.googleapis.com/maps/api/geocode/json?';
              const params = { 
                  key: "asdkfñlaskdGE",
                  address: "evergreen avenue",
                  city: "New York"
              };
              // this line takes the params object and builds the query string
              const query = Object.keys(params).map(k => `${esc(k)}=${esc(params[k])}`).join('&')
              const res = await fetch(url+query);
              const googleResponse = await res.json()
              

              随意复制此代码并将其粘贴到控制台上,看看它是如何工作的!!

              生成的 url 类似于:

              https://maps.googleapis.com/maps/api/geocode/json?key=asdkf%C3%B1laskdGE&address=evergreen%20avenue&city=New%20York
              

              这是我在决定写这篇文章之前一直在寻找的东西,享受吧:D

              【讨论】:

              • 谢谢卡洛斯。我忘了转义查询参数。
              猜你喜欢
              • 2020-12-02
              • 1970-01-01
              • 2018-11-08
              • 2021-03-22
              • 1970-01-01
              • 2013-04-06
              • 2014-06-15
              相关资源
              最近更新 更多