用 JavaScript 编码 URL?

如何使用 JavaScript 安全地编码 URL,以便可以将其放入 GET 字符串中?

var myUrl = "http://example.com/index.html?param=1&anotherParam=2";
var myOtherUrl = "http://example.com/index.html?url=" + myUrl;

我假设您需要在第二行编码myUrl变量?

答案

签出内置函数encodeURIComponent(str)encodeURI(str)
在您的情况下,这应该起作用:

var myOtherUrl = 
       "http://example.com/index.html?url=" + encodeURIComponent(myUrl);

您有三种选择:

  • escape()将不会编码: @*/+

  • encodeURI()将不会编码: ~!@#$&*()=:/,;?+'

  • encodeURIComponent()不会编码: ~!*()'

但在您的情况下,如果要将URL传递到其他页面的GET参数中,则应使用escapeencodeURIComponent ,而不要使用encodeURI

请参阅堆栈溢出问题最佳实践:转义,或 encodeURI / encodeURIComponent进行进一步的讨论。

坚持使用encodeURIComponent() 。函数encodeURI()不会麻烦编码许多在 URL 中具有语义重要性的字符(例如 “#”,“?” 和 “&”)。 escape()已被弃用,并且不会费心地对 “+” 字符进行编码,后者将被解释为服务器上的已编码空格(并且,如此处其他人所指出的那样,不会正确地对非 ASCII 字符进行 URL 编码)。

在其他地方encodeURI()encodeURIComponent()之间的区别有一个很好的解释 。如果您希望对某些内容进行编码,以便可以安全地将其包含为 URI 的组件(例如,作为查询字符串参数),则可以使用encodeURIComponent()

最好的答案是对查询字符串中的 (以及其他任何地方)使用encodeURIComponent

但是,我发现许多 API 都希望将 “” 替换为 “ +”,因此我不得不使用以下内容:

const value = encodeURIComponent(value).replace('%20','+');
const url = 'http://example.com?lang=en&key=' + value

escape在不同的浏览器中实现的方式有所不同, encodeURI不会对许多字符进行编码(例如#和甚至 /),而是将其用于完整的 URI / URL 而不会破坏它 - 这不是超级有用或安全的做法。

就像 @Jochem 在下面指出的那样,您可能想在每个文件夹名称上使用encodeURIComponent() ,但是由于这些原因,这些 API 似乎都不希望在文件夹名称中使用+ ,因此普通的老式encodeURIComponent效果很好。

例:

const escapedValue = encodeURIComponent(value).replace('%20','+');
const escapedFolder = encodeURIComponent('My Folder'); // no replace
const url = `http://example.com/${escapedFolder}/?myKey=${escapedValue}`;

如果您使用的是 jQuery,我将使用$.param方法。它使用 URL 编码将对象映射到值的字段,这比在每个值上调用转义方法更容易阅读。

$.param({a:"1=2", b:"Test 1"}) // gets a=1%3D2&b=Test+1

encodeURIComponent()是必经之路。

var myOtherUrl = "http://example.com/index.html?url=" + encodeURIComponent(myUrl);

但是请记住,与 php 版本的urlencode()略有不同,正如 @CMS 所述,它不会对每个字符进行编码。 http://phpjs.org/functions/urlencode / 的家伙将 js 等效于phpencode()

function urlencode(str) {
  str = (str + '').toString();

  // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current
  // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
  return encodeURIComponent(str)
    .replace('!', '%21')
    .replace('\'', '%27')
    .replace('(', '%28')
    .replace(')', '%29')
    .replace('*', '%2A')
    .replace('%20', '+');
}

如前所述,要对 URL 进行编码,您有两个功能:

encodeURI()

encodeURIComponent()

两者都存在的原因是,第一个保留了 URL,但有使太多内容无法逃脱的风险,而第二个则对所需的所有内容进行了编码。

对于第一个,您可以将新转义的 URL 复制到地址栏中(例如),它可以工作。但是,未转义的 “&” 会干扰字段定界符,“=” 会干扰字段名和值,而 “+” 则看起来像空格。但是对于简单数据,当您想要保留要转义的 URL 的本性时,这是可行的。

第二个是您需要做的所有事情,以确保字符串中的任何内容都不会干扰 URL。它保留了各种不重要的字符,从而使 URL 尽可能保持人类可读性,而不会受到干扰。如果不进行转义,则以这种方式编码的 URL 将不再用作 URL。

因此,如果可以的话,您总是想使用 encodeURIComponent()-在添加名称 / 值对之前,使用此函数对名称和值进行编码,然后再将其添加到查询字符串中。

我在艰难时期想出使用 encodeURI()的理由 - 我会将其留给聪明的人。

我尝试使用普通 javascript 进行的类似操作

function fixedEncodeURIComponent(str){
     return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
}

为了防止双重编码,最好在编码之前对 url 进行解码(例如,如果要处理用户输入的 url,可能已经编码了)。

可以说我们有abc%20xyz 123作为输入(已经编码了一个空格):

encodeURI("abc%20xyz 123")            //   wrong: "abc%2520xyz%20123"
encodeURI(decodeURI("abc%20xyz 123")) // correct: "abc%20xyz%20123"

什么都没有为我工作。我所看到的只是登录页面的 HTML,它返回到客户端,代码为 200。(最初是 302,但同一 Ajax 请求正在另一个 Ajax 请求中加载登录页面,这应该是重定向而不是简单地加载登录页面的文本)。

在登录控制器中,我添加了以下行:

Response.Headers["land"] = "login";

在全局 Ajax 处理程序中,我这样做:

$(function () {
    var $document = $(document);
    $document.ajaxSuccess(function (e, response, request) {
        var land = response.getResponseHeader('land');
        var redrUrl = '/login?ReturnUrl=' + encodeURIComponent(window.location);
        if(land) {
            if (land.toString() === 'login') {
                window.location = redrUrl;
            }
        }
    });
});

现在,我没有任何问题,它就像一个护身符。