如何使用 Javascript 构建查询字符串

Posted

技术标签:

【中文标题】如何使用 Javascript 构建查询字符串【英文标题】:How to build query string with Javascript 【发布时间】:2010-09-23 22:13:11 【问题描述】:

只是想知道 javascript 是否有任何内置的东西可以接受表单并返回查询参数,例如:"var1=value&var2=value2&arr[]=foo&arr[]=bar..."

多年来我一直在想这个问题。

【问题讨论】:

仅供参考:phpjs.org/functions/http_build_query Create query parameters in javascript的可能重复 【参考方案1】:

The URLSearchParams API 在所有现代浏览器中都可用。例如:

const params = new URLSearchParams(
  var1: "value",
  var2: "value2",
  arr: "foo",
);
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"

【讨论】:

这里是 imo 的最佳答案。只是为了添加它,您可以稍后在更复杂的场景中添加新的搜索参数params.append(key, value) 请注意,最终字符串中包含未定义和空值:x=null&y=undefined 另外,如果你已经有一个URL对象(例如const url = new URL("https://***.com")),你可以设置它的查询字符串url.search = new URLSearchParams(foo: "bar")或者url.searchParams.append("foo", "bar") 请注意,TS 会警告使用普通对象,但它仍然可以正常工作 @pomber 有什么好的想法可以过滤掉那些未定义的项目吗?【参考方案2】:

2k20 更新:将Josh's 解决方案与URLSearchParams.toString() 结合使用。

旧答案:


没有 jQuery

var params = 
    parameter1: 'value_1',
    parameter2: 'value 2',
    parameter3: 'value&3' 
;

var esc = encodeURIComponent;
var query = Object.keys(params)
    .map(k => esc(k) + '=' + esc(params[k]))
    .join('&');

对于不支持需要 ES5 的箭头函数语法的浏览器,将 .map... 行更改为

    .map(function(k) return esc(k) + '=' + esc(params[k]);)

【讨论】:

我见过的最好的解决方案 - 非常干净简洁。不过,有几点需要注意。 1) 在 .map() 中,k 和 params[k] 都应该被编码,例如encodeURIComponent(k) 和 encodeURIComponent(params[k])。 2) 查询字符串中允许有多个命名参数的实例。如果您想要该功能,则必须使用数组而不是对象(大多数应用程序不希望或不需要它)。 3) 并非所有浏览器都支持箭头函数语法(需要 ES5)。如果要支持所有浏览器(并对部分进行编码),请将上面的 .map() 替换为 .map(function(k) return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);) "没有足够的 jquery" 超级优雅紧凑。 @user1738579 我编辑了答案以包括您的非 ES5 示例。【参考方案3】:

如果您使用 jQuery,您可能需要查看 jQuery.param() http://api.jquery.com/jQuery.param/

例子:

var params = 
    parameter1: 'value1',
    parameter2: 'value2',
    parameter3: 'value3' 
;
var query = $.param(params);
console.log(query);

这将打印出来:

parameter1=value1&parameter2=value2&parameter3=value3

【讨论】:

这其实是正确答案!表单的查询字符串是$.param($('#myform').serializeArray()) @Jesse,这将与以下结果相同:$('#myform').serialize() jQuery !== JavaScript @gphilip 这就是为什么我以“如果您使用 jQuery ...”开始回复。否则,如果您想在 vanilla JS 中实现它,您可以在此处检查 jQuery.param() 的实现 github.com/jquery/jquery/blob/master/src/serialize.js :) 与我的回答不同,这个支持嵌套对象,如someStr=value1&someObj[a]=5&someObj[b]=6&someArr[]=1&someArr[]=2【参考方案4】:

这不会直接回答您的问题,但这是一个通用函数,它将创建一个包含查询字符串参数的 URL。参数(名称和值)被安全地转义以包含在 URL 中。

function buildUrl(url, parameters)
  var qs = "";
  for(var key in parameters) 
    var value = parameters[key];
    qs += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
  
  if (qs.length > 0)
    qs = qs.substring(0, qs.length-1); //chop off last "&"
    url = url + "?" + qs;
  
  return url;


// example:
var url = "http://example.com/";

var parameters = 
  name: "George Washington",
  dob: "17320222"
;

console.log(buildUrl(url, parameters));
// => http://www.example.com/?name=George%20Washington&dob=17320222

【讨论】:

在 jquery、mootools 等流行的 javascript 框架之一中是否有与此类似的内置功能...? 更强大的原生 JavaScript 解决方案位于 ***.com/a/1714899/1269037 有史以来最奇怪的实现,为什么在实际将new Array 用作对象时需要初始化它? o,o @UmutSirin Lol 是的,当时我对 Javascript 知之甚少。 xD 我想我把它当作一个 PHP 数组来对待。如果需要,请随意重构。 @Michael 哈哈,是的。我刚刚发送了一个编辑。谢谢你的回答!【参考方案5】:

创建一个URL 对象并将值附加到seachParameters

let stringUrl = "http://www.google.com/search";
let url = new URL(stringUrl);
let params = url.searchParams;
params.append("q", "This is seach query");

console.log(url.toString());

输出将是

http://www.google.com/search?q=This+is+seach+query

【讨论】:

这是最佳答案【参考方案6】:

ES2017 (ES8)

使用Object.entries(),它返回对象的[key, value] 对数组。例如,对于a: 1, b: 2,它将返回[['a', 1], ['b', 2]]。只有 IE 不支持(也不会)。

代码:

const buildURLQuery = obj =>
      Object.entries(obj)
            .map(pair => pair.map(encodeURIComponent).join('='))
            .join('&');

示例:

buildURLQuery(name: 'John', gender: 'male');

结果:

"name=John&gender=male"

【讨论】:

改用url.spec.whatwg.org/#urlsearchparams【参考方案7】:

使用 jQuery,您可以通过 $.param 做到这一点

$.param( action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' )

// -> "action=ship&order_id=123&fees%5B%5D=f1&fees%5B%5D=f2&label=a+demo"

【讨论】:

【参考方案8】:

querystring 可以帮忙。

所以,你可以

const querystring = require('querystring')

url += '?' + querystring.stringify(parameters)

【讨论】:

对于前端应用你也可以考虑npmjs.com/package/qs @RobertPankowecki,是的,qs 更好,并且已经在我的武器库中,干杯!【参考方案9】:

不,我不认为标准 JavaScript 内置了该功能,但 Prototype JS 具有该功能(当然大多数其他 JS 框架也有,但我不知道它们),他们称之为serialize。

我可以推荐 Prototype JS,它工作得很好。我真正注意到的唯一缺点是它的大小(几百 kb)和范围(ajax、dom 等的大量代码)。因此,如果您只想要一个表单序列化程序,那就太过分了,严格来说,如果您只想要它的 Ajax 功能(这主要是我使用它的目的),那就太过分了。除非你很小心,否则你可能会发现它做了太多的“魔法”(比如使用 Prototype JS 函数扩展它接触到的每个 dom 元素只是为了找到元素)使其在极端情况下变慢。

【讨论】:

只是想知道是否有内置的东西。好像应该有。我讨厌原型,但我不反对你:) 在设计 JavaScript 时,还没有发现 Ajax,因此解析表单只是为了获取查询字符串(提交时它会自行创建)可能没有多大意义。今天确实如此,艰难...顺便说一句,与 script.aculo.us 相比,原型 nice。 :)【参考方案10】:

如果您不想使用库,这应该涵盖大多数/所有相同的表单元素类型。

function serialize(form) 
  if (!form || !form.elements) return;

  var serial = [], i, j, first;
  var add = function (name, value) 
    serial.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
  

  var elems = form.elements;
  for (i = 0; i < elems.length; i += 1, first = false) 
    if (elems[i].name.length > 0)  /* don't include unnamed elements */
      switch (elems[i].type) 
        case 'select-one': first = true;
        case 'select-multiple':
          for (j = 0; j < elems[i].options.length; j += 1)
            if (elems[i].options[j].selected) 
              add(elems[i].name, elems[i].options[j].value);
              if (first) break; /* stop searching for select-one */
            
          break;
        case 'checkbox':
        case 'radio': if (!elems[i].checked) break; /* else continue */
        default: add(elems[i].name, elems[i].value); break;
      
    
  

  return serial.join('&');

【讨论】:

谢谢!我刚刚面临与原始海报相同的问题,而您的功能正是我所需要的。【参考方案11】:

您现在可以使用 FormDataURLSearchParams 做到这一点,而无需循环任何内容。

const formData = new FormData(form);
const searchParams = new URLSearchParams(formData);
const queryString = searchParams.toString();

不过,较旧的浏览器需要 polyfill。

【讨论】:

【参考方案12】:

可能有点多余,但我发现的最简洁的方法是建立在此处的一些答案之上的:

const params: 
   key1: 'value1',
   key2: 'value2',
   key3: 'value3',


const esc = encodeURIComponent;
const query = Object.keys(params)
  .map(k => esc(k) + '=' + esc(params[k]))
  .join('&');

return fetch('my-url', 
  method: 'POST',
  headers: 'Content-Type': 'application/x-www-form-urlencoded',
  body: query,
)

Source

【讨论】:

【参考方案13】:

我自己并不完全确定,我记得曾在一定程度上看到过 jQuery,但它根本不处理分层记录,更不用说以 php 友好的方式了。

我确实知道的一件事是,在构建 URL 并将产品粘贴到 dom 中时,不要只使用字符串胶水来执行此操作,否则您将自己打开一个方便的分页器。

例如,某些广告软件会从运行您的闪存的任何程序中嵌入版本字符串。当它的 adobes 通用简单字符串时这很好,但是,这非常幼稚,并且对于安装了 Gnash 的人来说会陷入尴尬的混乱,因为 gnash 的版本字符串恰好包含完整的 GPL 版权许可,并带有 URL和 标签。在您的字符串胶水广告客户生成器中使用它会导致页面打开并且在 dom 中出现不平衡的 html

故事的寓意:

   var foo = document.createElement("elementnamehere"); 
   foo.attribute = allUserSpecifiedDataConsideredDangerousHere; 
   somenode.appendChild(foo); 

不是:

   document.write("<elementnamehere attribute=\"" 
        + ilovebrokenwebsites 
        + "\">" 
        + stringdata 
        + "</elementnamehere>");

Google 需要学习这个技巧。我试图报告这个问题,他们似乎不在乎。

【讨论】:

正确。 Document.write 是所以 1995,无论如何。【参考方案14】:

您实际上并不需要一个表单来使用 Prototype 执行此操作。只需使用Object.toQueryString function:

Object.toQueryString( action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' )

// -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'

【讨论】:

当然,您在近 10 年前就回答了,但现在已弃用此代码。【参考方案15】:

正如 Stein 所说,您可以使用来自 http://www.prototypejs.org 的原型 javascript 库。 包含 JS 就很简单了,$('formName').serialize() 会返回你想要的!

【讨论】:

【参考方案16】:

对于我们这些喜欢 jQuery 的人,您可以使用表单插件:http://plugins.jquery.com/project/form,其中包含一个 formSerialize 方法。

【讨论】:

【参考方案17】:

我知道这是很晚的答案,但效果很好......

var obj = 
a:"a",
b:"b"


Object.entries(obj).map(([key, val])=>`$key=$val`).join("&");

注意:object.entries 将返回键值对

上面一行的输出将是 a=a&b=b

希望它对某人有所帮助。

快乐编码...

【讨论】:

【参考方案18】:

现在回答您的问题可能为时已晚。 我有同样的问题,我不想继续附加字符串来创建 URL。所以,我开始使用 $.param 作为techhouse 解释。 我还找到了一个URI.js 库,可以轻松地为您创建 URL。有几个示例可以帮助您:URI.js Documentation。 这是其中之一:

var uri = new URI("?hello=world");
uri.setSearch("hello", "mars"); // returns the URI instance for chaining
// uri == "?hello=mars"

uri.setSearch( foo: "bar", goodbye : ["world", "mars"] );
// uri == "?hello=mars&foo=bar&goodbye=world&goodbye=mars"

uri.setSearch("goodbye", "sun");
// uri == "?hello=mars&foo=bar&goodbye=sun"

// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.setSearch("foo", ["bar", "baz"]);
uri.setSearch("foo[]", ["bar", "baz"]);`

【讨论】:

【参考方案19】:

这些答案非常有帮助,但我想添加另一个答案,它可以帮助您构建完整的 URL。 这可以帮助您连接基础 urlpathhashparameters

var url = buildUrl('http://mywebsite.com', 
        path: 'about',
        hash: 'contact',
        queryParams: 
            'var1': 'value',
            'var2': 'value2',
            'arr[]' : 'foo'
        
    );
    console.log(url);

您可以通过npm下载https://www.npmjs.com/package/build-url

演示:

;(function () 
  'use strict';

  var root = this;
  var previousBuildUrl = root.buildUrl;

  var buildUrl = function (url, options) 
    var queryString = [];
    var key;
    var builtUrl;
    var caseChange; 
    
    // 'lowerCase' parameter default = false,  
    if (options && options.lowerCase) 
        caseChange = !!options.lowerCase;
     else 
        caseChange = false;
    

    if (url === null) 
      builtUrl = '';
     else if (typeof(url) === 'object') 
      builtUrl = '';
      options = url;
     else 
      builtUrl = url;
    

    if(builtUrl && builtUrl[builtUrl.length - 1] === '/') 
      builtUrl = builtUrl.slice(0, -1);
     

    if (options) 
      if (options.path) 
          var localVar = String(options.path).trim(); 
          if (caseChange) 
            localVar = localVar.toLowerCase();
          
          if (localVar.indexOf('/') === 0) 
              builtUrl += localVar;
           else 
            builtUrl += '/' + localVar;
          
      

      if (options.queryParams) 
        for (key in options.queryParams) 
          if (options.queryParams.hasOwnProperty(key) && options.queryParams[key] !== void 0) 
            var encodedParam;
            if (options.disableCSV && Array.isArray(options.queryParams[key]) && options.queryParams[key].length) 
              for(var i = 0; i < options.queryParams[key].length; i++) 
                encodedParam = encodeURIComponent(String(options.queryParams[key][i]).trim());
                queryString.push(key + '=' + encodedParam);
              
             else               
              if (caseChange) 
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim().toLowerCase());
              
              else 
                encodedParam = encodeURIComponent(String(options.queryParams[key]).trim());
              
              queryString.push(key + '=' + encodedParam);
            
          
        
        builtUrl += '?' + queryString.join('&');
      

      if (options.hash) 
        if(caseChange)
            builtUrl += '#' + String(options.hash).trim().toLowerCase();
        else
            builtUrl += '#' + String(options.hash).trim();
      
     
    return builtUrl;
  ;

  buildUrl.noConflict = function () 
    root.buildUrl = previousBuildUrl;
    return buildUrl;
  ;

  if (typeof(exports) !== 'undefined') 
    if (typeof(module) !== 'undefined' && module.exports) 
      exports = module.exports = buildUrl;
    
    exports.buildUrl = buildUrl;
   else 
    root.buildUrl = buildUrl;
  
).call(this);


var url = buildUrl('http://mywebsite.com', 
		path: 'about',
		hash: 'contact',
		queryParams: 
			'var1': 'value',
			'var2': 'value2',
			'arr[]' : 'foo'
		
	);
	console.log(url);

【讨论】:

【参考方案20】:

var params =  width:1680, height:1050 ;
var str = jQuery.param( params );

console.log(str)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案21】:

UrlSearchParams API 是一个很好的建议,但我不敢相信没有人提到非常有用的 .get.set 方法。它们可用于操作查询字符串,不仅非常易于使用,而且还解决了您可能遇到的许多问题。例如,就我而言,我想构建一个没有重复键的查询字符串。 .set 为您解决了这个问题。引用自MDN docs:

URLSearchParams.set() 将与给定搜索参数关联的值设置为给定值。如果有多个值,则删除其他值。

示例 (from MDN):

let url = new URL('https://example.com?foo=1&bar=2');
let params = new URLSearchParams(url.search);

// Add a third parameter.
params.set('baz', 3);
params.toString(); // "foo=1&bar=2&baz=3"

替代的,更短的语法:

let url = new URL('https://example.com?foo=1&bar=2');

// Add a third parameter.
url.searchParams.set('baz', 3);
params.toString(); // "foo=1&bar=2&baz=3"

【讨论】:

以上是关于如何使用 Javascript 构建查询字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 javascript 从 Web 服务返回的二进制字符串构建 PDF 文件

如何使用 java 对从 javascript 到 servletpage 的查询字符串进行编码和解码?

如何在 JavaScript 中删除查询字符串参数?

如何在 JavaScript 中获取查询字符串值?

如何在 JavaScript 中获取查询字符串值?

如何在 JavaScript 中获取查询字符串值?