如何在我的 javascript 中构建一个有效的 url

how to build a valid url inside my javascript

我有以下 JavaScript,它根据用户输入构建 url 参数:-

$(document).ready(function(){

    $('#button').click(function(e) {  
        var count=1;
        var s="";

        var inputvalue = $("#journal").val();
        var inputvalue2 = $("#keywords").val();
        var inputvalue3 = $("#datepub").val();
        var inputvalue4 = $("#title").val();
        var inputvalue5 = $("#localcurrency").val();
        var inputvalue6 = $("#locations").val();
        var inputvalue7 = $("#dropdown1").val();
        var inputvalue8 = $("#dropdown2").val();

        if(inputvalue!=null && inputvalue!="")
        {
        s = s+ "FilterField"+count+"=Journal&FilterValue"+count+"="+inputvalue+"&";
        count++;
        }
        if(inputvalue2!=null && inputvalue2!="")
        {
        s = s+ "FilterField"+count+"=KeyWords&FilterValue"+count+"="+inputvalue2+"&";
        count++;
        }
        if(inputvalue3!=null && inputvalue3!="")
        {
        s = s+ "FilterField"+count+"=datepub&FilterValue"+count+"="+inputvalue3+"&";
        count++;
        }
        if(inputvalue4!=null && inputvalue4!="")
        {
        s = s+ "FilterField"+count+"=Title&FilterValue"+count+"="+inputvalue4+"&";
        count++;
        }
        if(inputvalue5!=null && inputvalue5!="")
        {
        s = s+ "FilterField"+count+"=localcurrency&FilterValue"+count+"="+inputvalue5+"&";
        count++;
        }
        if(inputvalue6!=null && inputvalue6!="")
        {
        s = s+ "FilterField"+count+"=locations&FilterValue"+count+"="+inputvalue6+"&";
        count++;
        }
        if(inputvalue7!=null && inputvalue7!="")
        {
        s = s+ "FilterField"+count+"=dropdown1&FilterValue"+count+"="+inputvalue7+"&";
        count++;
        }
        if(inputvalue8!=null && inputvalue8!="")
        {
        s = s+ "FilterField"+count+"=dropdown2&FilterValue"+count+"="+inputvalue8+"&";
        count++;
        }

        window.location.replace("/teamsites/Bib%20Test/Forms/search.aspx?"+s);

    });
});
</script> 

现在上面的脚本将生成 URLs 例如

http://***/teamsites/Bib%20Test/Forms/search.aspx?FilterField1=Journal&FilterValue1=123

http://***/teamsites/Bib%20Test/Forms/search.aspx?FilterField1=Journal&FilterValue1=123&FilterField2=localcurrency&FilterValue2=USD&

一切正常,直到我尝试传递一个包含 & 的搜索参数。例如,我想搜索其日志 = General&Procedure 的记录,因此使用我上面的代码,URL 将如下所示:-

http://***/teamsites/Bib%20Test/Forms/search.aspx?FilterField1=Journal&FilterValue1=General&Procedure&

我没有得到任何结果,因为应用程序假定 Procudure 是一个参数而不是 FilterValue1 的一部分。现在要解决这个特定问题,我定义为使用 encodeURIComponent() 函数构建 URL 参数,如下所示:-

var inputvalue = encodeURIComponent($("#journal").val());
var inputvalue2 = encodeURIComponent($("#keywords").val());
var inputvalue3 = encodeURIComponent($("#datepub").val());
var inputvalue4 = encodeURIComponent($("#title").val());
var inputvalue5 = encodeURIComponent($("#localcurrency").val());
var inputvalue6 = encodeURIComponent($("#locations").val());
var inputvalue7 = encodeURIComponent($("#dropdown1").val());
var inputvalue8 = encodeURIComponent($("#dropdown2").val());

现在生成的 URL 将如下所示:-

http://***teamsites/Bib%20Test/Forms/search.aspx?FilterField1=Journal&FilterValue1=General%26Procedure

我得到了预期的结果.. 但不确定使用 encodeURIComponent() 仅对参数值进行编码是否是一个有效的修复,因为我似乎将对 & 进行编码,如果它是查询字符串参数的一部分,但仍然 url 包含未编码的 & 将 url 参数分开.. 现在我从上次 url 得到的结果是正确的.. 但不确定我做的事情是否正确?是否有内置功能可以帮我完成这项工作?? 谢谢

我为此使用 encodeUriComponent

url += "&filter=" + encodeURIComponent(filter);

你想对参数值中的'&'进行编码,所以你在参数值上使用'encodeURIComponent',但你不想对参数之间的东西进行编码。

/!\ 这不是答案

关于评论

const [
   $("#journal").val(),
   $("#keywords").val(),
   $("#datepub").val(),
   $("#title").val(),
   // ...
].forEach((x) => {
   if (x !== null && x !== '') {
     s += ...;

     count += 1;
   }
});

以下是 URL 语法的来源:

您会注意到查询组件的确切内容并未标准化。它的 simple definition 是:

The query component is indicated by the first question mark ("?") character and terminated by a number sign ("#") character or by the end of the URI.

然而,事实上的标准是使用&(&)字符作为分隔符。按照这个约定,任何时候这个字符也出现在你的数据中并且不是分隔符,你必须“percent-encode”它,as per the standard

A percent-encoding mechanism is used to represent a data octet in a component when that octet's corresponding character is outside the allowed set or is being used as a delimiter of, or within, the component.

您会很容易理解其他特殊字符,如 =%#,如果它们出现在您的数据中,也必须进行百分比编码。编码更多特殊字符也没有坏处。

因此,如果您遵循此约定,您的查询组件应采用以下形式:

?field1=value1&field2=value2

每个 fieldvalue 都进行百分比编码。在JavaScript中,确实可以方便的使用encodeURIComponent功能。不要忘记对字段进行编码!

此外,由于您的用例非常常见,因此有很多可用的库可以为您处理此类转换,例如URI.js.

但是既然你提到使用jQuery,你可以方便地使用jQuery.param来进行转换:

Create a serialized representation of an array, a plain object, or a jQuery object suitable for use in a URL query string or Ajax request. In case a jQuery object is passed, it should contain input elements with name/value properties.

$(document).ready(function() {
  $('#button').click(retrieveInputsValues);

  retrieveInputsValues();
});

function retrieveInputsValues() {
  var inputIds = [
    'Journal',
    'KeyWords',
    'datepub',
    'Title',
    'localcurrency',
    'locations',
    'dropdown1',
    'dropdown2'
  ];
  var obj = {};
  var count = 1;
  var value;

  for (var i = 0; i < inputIds.length; i += 1) {
    value = $('#' + inputIds[i].toLowerCase()).val();
    if (value !== null && value !== '') {
      obj['FilterField' + count] = inputIds[i];
      obj['FilterValue' + count] = value;
      count += 1;
    }
  }

  console.log($.param(obj));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
Journal
<input type="text" id="journal" value="test & ampersand, comma, % percent, = equal and space" />
<br />keywords <input type="text" id="keywords" />

<br />datepub
<select id="datepub">
  <option value=""></option>
  <option value="1950">1950</option>
  <option value="2010">2010</option>
  <option value="2017" selected>2017</option>
  <option value="audi">Audi</option>
</select>
<br />title
<select id="title">
  <option value=""></option>
  <option value="TestDoc">test doc</option>
  <option value="t">t</option>
</select>
<br />localcurrency
<select id="localcurrency">
  <option value=""></option>
  <option value="USD">USD</option>
</select>
<br />locations
<select id="locations">
  <option value=""></option>
  <option value="US">US</option>
  <option value="UK">UK</option>
</select>
<br />dropdown1
<select id="dropdown1">
  <option value=""></option>
  <option value="a">a</option>
  <option value="b">b</option>
</select>
<br />dropdown2
<select id="dropdown2">
  <option value=""></option>
  <option value="aa">aa</option>
  <option value="bb">bb</option>
  <option value="cc">cc</option>
  <option value="dd">dd</option>
</select>
<br />
<button type="button" id="button">search</button>
<!-- re-used from  -->

顺便说一句,通常不需要将字段名称作为值传递,只需使用“field=value”即可。

但是您的后端处理可能有特定的用例?

如果您不关心 Internet Explorer 或 Edge,请使用此选项。

我建议改用浏览器的 URL API。它很稳定,并且在大多数现代浏览器中都可用,可以在本地处理 URL 特定工作。

您的代码可以更改如下以使用此 API。它会根据规范自动编码所有必需的参数。您无需手动处理查询参数。

$(document).ready(function() {

  $('#button').click(function(e) {
    var count = 1;
    var s = "";
    var url = new URL("http://yourhost.com/teamsites/Bib%20Test/Forms/search.aspx");

    var inputvalue = $("#journal").val();
    var inputvalue2 = $("#keywords").val();
    var inputvalue3 = $("#datepub").val();
    var inputvalue4 = $("#title").val();
    var inputvalue5 = $("#localcurrency").val();
    var inputvalue6 = $("#locations").val();
    var inputvalue7 = $("#dropdown1").val();
    var inputvalue8 = $("#dropdown2").val();

    if (inputvalue != null && inputvalue != "") {
      url.searchParams.set("FilterField" + count, "Journal");
      url.searchParams.set("FilterValue" + count, inputvalue);
      count++;
    }

    if (inputvalue2 != null && inputvalue2 != "") {
      url.searchParams.set("FilterField" + count, "KeyWords");
      url.searchParams.set("FilterValue" + count, inputvalue2);
      count++;
    }

    if (inputvalue3 != null && inputvalue3 != "") {
      url.searchParams.set("FilterField" + count, "datepub");
      url.searchParams.set("FilterValue" + count, inputvalue3);
      count++;
    }

    if (inputvalue4 != null && inputvalue4 != "") {
      url.searchParams.set("FilterField" + count, "Title");
      url.searchParams.set("FilterValue" + count, inputvalue4);
      count++;
    }

    if (inputvalue5 != null && inputvalue5 != "") {
      url.searchParams.set("FilterField" + count, "localcurrency");
      url.searchParams.set("FilterValue" + count, inputvalue5);
      count++;
    }

    if (inputvalue6 != null && inputvalue6 != "") {
      url.searchParams.set("FilterField" + count, "locations");
      url.searchParams.set("FilterValue" + count, inputvalue6);
      count++;
    }

    if (inputvalue7 != null && inputvalue7 != "") {
      url.searchParams.set("FilterField" + count, "dropdown1");
      url.searchParams.set("FilterValue" + count, inputvalue7);
      count++;
    }

    if (inputvalue8 != null && inputvalue8 != "") {
      url.searchParams.set("FilterField" + count, "dropdown2");
      url.searchParams.set("FilterValue" + count, inputvalue8);
      count++;
    }

    window.location.replace(url.href);

  });
});

除此之外,我建议结合@GrégoryNEUT 的建议,因为它使代码简洁易读。

扩展我的 作为答案。

使用encodeURIComponent不仅有效而且正确,它实际上是支持值中特殊字符的唯一修复方法在 URL 中对 URL.

有特殊意义

编码 URL 组件中的值对于防止 XSS 攻击也很重要。看看here

URL-escaping is susceptible to double-escaping, meaning you must URL-escape its parts exactly once. It is best to perform the URL-escaping at the time the URL is being assembled.

不过,您可以通过以下方式改进您的代码

var inputs = [ "#journal", "#keywords", "#datepub", "#title", "#localcurrency", "#locations", "#dropdown1", "#dropdown2" ];
$(document).ready(function(){
    $('#button').click(function(e) {  
        var count =  1;
        var searchParams = inputs.filter( function( id ){
            return $( "#" + id ).val().trim().length > 0;
        }).map( function( id ){
            var value = encodeURIComponent( $( "#" + id ).val().trim() );
            return "FilterField" + (count) + "=" + id + "&FilterValue" + (count++) + "=" + value;
        }).join( "&" );
        window.location.replace("/teamsites/Bib%20Test/Forms/search.aspx?"+ searchParams );
    });
});

或者,您也可以使用 URL (though not supported in IE)

var inputs = [ "#journal", "#keywords", "#datepub", "#title", "#localcurrency", "#locations", "#dropdown1", "#dropdown2" ];
$(document).ready(function(){
    $('#button').click(function(e) {  
        var count =  1;
        var url = new URL( "/teamsites/Bib%20Test/Forms/search.aspx?", window.location.origin );        
        inputs.forEach( function( id ){
            var value = encodeURIComponent( $( "#" + id ).val().trim() );
            if ( value.length >  0 )
            {
                url.searchParams.append( "FilterField" + count, id );
                url.searchParams.append( "FilterValue" + (count++), value );
            }
        });
        window.location.replace( url.href );
    });
});

如您所见,在这种方法中,您也必须使用 encodeURIcomponent,因为根据 spec

The append(name, value) method, when invoked, must run these steps:

Append a new name-value pair whose name is name and value is value, to list.

Run the update steps.

不能保证一定会完成编码。 所以,显式编码是必要的!!