在 JavaScript 中对 URL 进行编码

Encode URL in JavaScript

提问人:nickf 提问时间:12/2/2008 最后编辑:Peter Mortensennickf 更新时间:5/30/2023 访问量:1904860

问:

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

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

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

javascript url 编码 urlencode

评论

31赞 Zack The Human 12/2/2008
尝试查看 encodeURI()decodeURI()。
1赞 phillihp 9/18/2012
您可以在此处使用此工具:phillihp.com/toolz/url-encode-decode
1赞 Yanni 7/1/2011
请参阅 JavaScript urlencode 函数
4赞 Andrew 3/3/2018
编码URIComponent()
1赞 iron9 6/2/2021
请去看这个答案,因为它是唯一一个使用现代 javascript 功能的答案(除 Internet Explorer 外,其他任何功能都支持)。

答:

3183赞 Buu 12/2/2008 #1

查看内置函数 encodeURIComponent(str) 和 encodeURI(str)。
就您而言,这应该有效:

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

评论

13赞 hitautodestruct 10/28/2012
添加@cms给出的解释怎么样? 也是一个有效的选项。escape
13赞 Ifnot 3/2/2013
根据 @CMS 对于 URL 编码来说并不安全。encodeURI
18赞 Buu 3/7/2013
@AnaelFavre因为它旨在对整个 URL 进行编码,其中不允许使用 、 等字符。这两种方法不能互换使用,您必须知道要编码什么才能使用正确的方法。:/@
4赞 Scotty Jamison 5/15/2022
注意:encodeURIComponent 仅用于 URL 的路径。查询参数遵循较旧的百分比编码规范,该规范要求空格编码为“+”而不是“%20”。请参阅此 SO 问题以了解更多信息。某些服务器可能会对这种不正确的编码很宽松,但您的里程可能会有所不同。在现代 JavaScript 中,我建议通过 URL 或 URLSearchParams 进行编码,正如这个答案所建议的那样。
1687赞 Christian C. Salvadó 12/2/2008 #2

您有三种选择:

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

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

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

但在你的情况下,如果你想将一个URL传递到其他页面的参数中,你应该使用或,而不是。GETescapeencodeURIComponentencodeURI

有关进一步讨论,请参阅 Stack Overflow 问题最佳实践:转义或 encodeURI/encodeURIComponent

评论

86赞 erickson 12/2/2008
用于转义的字符编码是可变的。坚持使用 UTF-8 的 encodeURI 和 encodeURIComponent。
4赞 kevzettler 1/30/2011
我正在使用 encodeURIComponent 并注意到它不会对管道字符进行编码 |
15赞 nickf 1/31/2011
@kevzettler - 为什么要这样做?管道在 URI 中不具有语义重要性。
8赞 opteronn 3/6/2010
小心。该转义将非 ASCII 字符转换为其 Unicode 转义序列,如 .%uxxx
4赞 Tseng 9/4/2013
@GiovanniP:允许德语、法语、日语、中文、阿拉伯语字符作为输入并通过 GET 或 POST 传递这些参数的人。
205赞 Mike Brennan 5/30/2011 #3

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

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

3赞 Asif Ashraf 6/22/2012 #4

没有什么对我有用。我看到的只是登录页面的 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;
            }
        }
    });
});

现在我没有任何问题,它就像一个魅力。

99赞 Ryan Taylor 12/15/2012 #5

最好的答案是使用查询字符串中的(而不是其他任何地方)。encodeURIComponent

但是,我发现许多较旧的 API 都想用“+”替换“ ”,所以我不得不使用以下内容:

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

escape在不同的浏览器中以不同的方式实现,并且不会对许多字符(如 # 甚至 /)进行编码——它被用于完整的 URI/URL 而不会破坏它——这不是超级有用或安全。encodeURI

正如@Jochem在下面指出的那样,您可能希望在(每个)文件夹名称上使用,但无论出于何种原因,这些 API 似乎都不希望使用文件夹名称,因此普通的旧名称效果很好。encodeURIComponent()+encodeURIComponent

例:

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

评论

26赞 Jochem Kuijpers 1/20/2013
请注意,您只能在第一个问号(这是 URL 的“查询”部分)之后将 %20 替换为 + 符号。假设我想浏览到 。它应该转换为:,但许多实现允许将查询字符串中的“%20”替换为“+”。但是,您不能在 URL 的路径部分中将 '%20' 替换为 '+',这将导致 Not Found 错误,除非您的目录带有 而不是空格。http://somedomain/this dir has spaces/info.php?a=this has also spaceshttp://somedomain/this%20dir%20has%spaces/info.php?a=this%20has%20also%20spaces+
0赞 Ryan Taylor 7/20/2013
@Jochem Kuijpers,你肯定不会把“+”放在目录中。我只会将其应用于查询参数值本身(或键,如果需要),而不是整个 URL,甚至整个查询字符串。
0赞 njzk2 6/3/2014
我会替换值而不是编码结果
1赞 Ryan Taylor 6/3/2014
不幸的是,@njzk2 会给你 ,所以你必须使用两个正则表达式......我想这就是为什么会这样,因为“+”是“”最终的编码方式不同。encodeURIComponent('+')%2B
0赞 xhienne 3/26/2019
没有理由将 %20 转换为“+”。ASCII 空间的有效转义序列是 %20,而不是 RFC 3986 (tools.ietf.org/html/rfc3986) 中未提及的“+”。“+”在 1990 年代使用;它现在已经过时,仅出于遗留原因才受支持。不要使用它。
43赞 Maksym Kozlenko 5/13/2013 #6

我建议使用 qs npm 包

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

它更容易与 JavaScript 对象一起使用,并且它为您提供了所有参数的正确 URL 编码。

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

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

评论

0赞 Maksym Kozlenko 9/10/2015
我认为提供的例子就足够了。如果您需要有关 $.param 的更多信息,请 api.jquery.com/jquery.param
0赞 Cyril Duchon-Doris 1/5/2017
几乎每个人都使用 jQuery,我确实觉得它而不是 encoreURIComponent 更舒服
0赞 JohanTG 4/20/2021
QS很棒,紧凑,实用的包装。在后端投票支持qs
6赞 3 revs, 3 users 62%Narayan Yerrabachu #7

我用普通 JavaScript 尝试过类似的事情:

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

评论

0赞 Peter Mortensen 12/8/2022
你能解释一下你的答案吗?例如,为什么是神奇的十六进制数“2A”?(即 ASCII 中的“*”(星号)。请通过编辑(更改)您的答案来回复,而不是在评论中(******************** 没有 ************************ “编辑:”、“更新:”或类似 - 答案应该看起来像今天写的一样)。
3赞 Sangeet Shah 9/10/2015 #8

编码 URL 字符串

var url = $(location).attr('href'); // Get the current URL

// Or
var url = 'folder/index.html?param=#23dd&noob=yes'; // Or specify one

var encodedUrl = encodeURIComponent(url);
console.log(encodedUrl);
// Outputs folder%2Findex.html%3Fparam%3D%2323dd%26noob%3Dyes

有关更多信息,请转到 jQuery 编码/解码 URL 字符串

15赞 Adam Fischer 10/1/2015 #9

encodeURIComponent() 是要走的路。

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

但是您应该记住,与PHP版本有细微的差异,正如@CMS提到的,它不会对每个字符进行编码。http://phpjs.org/functions/urlencode/ 的家伙使 JavaScript 等效于:urlencode()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', '+');
}
2赞 Mohith Maratt 9/27/2016 #10

您可以使用 ESAPI 库并使用以下函数对 URL 进行编码。该函数确保在对文本内容的其余部分进行编码时,'/'不会丢失:

function encodeUrl(url)
{
    String arr[] = url.split("/");
    String encodedUrl = "";
    for(int i = 0; i<arr.length; i++)
    {
        encodedUrl = encodedUrl + ESAPI.encoder().encodeForHTML(ESAPI.encoder().encodeForURL(arr[i]));
        if(i<arr.length-1) encodedUrl = encodedUrl + "/";
    }
    return url;
}

评论

0赞 Peter Mortensen 11/28/2022
原始 URL 重定向。上面有预期的内容吗?
7赞 serg 1/6/2017 #11

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

假设我们有输入(一个空格已经编码):abc%20xyz 123

encodeURI("abc%20xyz 123")            //   Wrong: "abc%2520xyz%20123"
encodeURI(decodeURI("abc%20xyz 123")) // Correct: "abc%20xyz%20123"
12赞 Gerard ONeill 1/27/2017 #12

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

encodeURI()

encodeURIComponent()

两者存在的原因是,前者保留了 URL,但存在遗漏太多未转义内容的风险,而后者则对所需的所有内容进行编码。

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

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

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

我很难想出使用 encodeURI() 的理由——我会把它留给更聪明的人。

10赞 Willem van der Veen 9/23/2018 #13

什么是URL编码:

当 URL 内有特殊字符时,应对 URL 进行编码。例如:

console.log(encodeURIComponent('?notEncoded=&+'));

在此示例中,我们可以观察到除字符串以外的所有字符都使用 % 符号编码。URL 编码也称为百分比编码,因为它使用 % 转义所有特殊字符。然后,在这个 % 符号之后,每个特殊字符都有一个唯一的代码notEncoded

为什么我们需要 URL 编码:

某些字符在 URL 字符串中具有特殊值。例如,?字符表示查询字符串的开头。为了在 Web 上成功定位资源,有必要区分字符是字符串的一部分还是 URL 结构的一部分。

我们如何在 JavaScript 中实现 URL 编码:

JavaScript 提供了一堆内置的实用程序函数,我们可以用它们来轻松地对 URL 进行编码。以下是两个方便的选项:

  1. encodeURIComponent():将 URI 的组件作为参数并返回编码的 URI 字符串。
  2. encodeURI():将 URI 作为参数并返回编码的 URI 字符串。

示例和注意事项:

请注意,不要将整个 URL(包括 scheme,例如 https://)传入 。这实际上可以将其转换为无法正常工作的 URL。例如:encodeURIComponent()

// for a whole URI don't use encodeURIComponent it will transform
// the / characters and the URL won't fucntion properly
console.log(encodeURIComponent("http://www.random.com/specials&char.html"));

// instead use encodeURI for whole URL's
console.log(encodeURI("http://www.random.com/specials&char.html"));

我们可以观察到,如果我们把整个 URL 放进去,正斜杠 (/) 也被转换为特殊字符。这将导致 URL 不再正常运行。encodeURIComponent

因此(顾名思义)使用:

  1. encodeURIComponent在要编码的 URL 的某个部分。
  2. encodeURI在您要编码的整个 URL 上。
3赞 Jonathan Applebaum 2/9/2019 #14

以下是 JavaScript 内置函数的现场演示encodeURIComponent()decodeURIComponent()

<!DOCTYPE html>
<html>
  <head>
    <style>
      textarea{
        width: 30%;
        height: 100px;
      }
    </style>
    <script>
      // Encode string to Base64
      function encode()
      {
        var txt = document.getElementById("txt1").value;
        var result = btoa(txt);
        document.getElementById("txt2").value = result;
      }
      // Decode Base64 back to original string
      function decode()
      {
        var txt = document.getElementById("txt3").value;
        var result = atob(txt);
        document.getElementById("txt4").value = result;
      }
    </script>
  </head>
  <body>
    <div>
      <textarea id="txt1">Some text to decode
      </textarea>
    </div>
    <div>
      <input type="button" id="btnencode" value="Encode" onClick="encode()"/>
    </div>
    <div>
      <textarea id="txt2">
      </textarea>
    </div>
    <br/>
    <div>
      <textarea id="txt3">U29tZSB0ZXh0IHRvIGRlY29kZQ==
      </textarea>
    </div>
    <div>
      <input type="button" id="btndecode" value="Decode" onClick="decode()"/>
    </div>
    <div>
      <textarea id="txt4">
      </textarea>
    </div>
  </body>
</html>
3赞 Arthur 10/6/2019 #15

使用函数严格遵守 RFC 3986fixedEncodeURIComponent

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
36赞 Qback 11/15/2019 #16

现代解决方案 (2021)

由于编写了其他答案,因此引入了 URLSearchParams API。它可以像这样使用:

const queryParams = { param1: 'value1', param2: 'value2' }
const queryString = new URLSearchParams(queryParams).toString()
// 'param1=value1&param2=value2'

它还对非 URL 字符进行编码。

对于您的特定示例,您可以像这样使用它:

const myUrl = "http://example.com/index.html?param=1&anotherParam=2";
const myOtherUrl = new URL("http://example.com/index.html");
myOtherUrl.search = new URLSearchParams({url: myUrl});
console.log(myOtherUrl.toString());

这里这里也提到了这个解决方案。

6赞 HoldOffHunger 5/17/2020 #17

不应直接使用 encodeURIComponent()。

看看RFC3986:统一资源标识符 (URI):通用语法

sub-delims = “!” / “$” / “&” / “'” / “(” / “)” / "*" / "+" / "," / ";" / "="

保留字符的用途是提供一组可与 URI 中的其他数据区分开来的分隔字符。

encodeURIComponent() 不会对 RFC3986 URI 定义的这些保留字符进行转义。

MDN Web 文档:encodeURIComponent()

为了更严格地遵守 RFC 3986(保留 !、'、(、) 和 *),即使这些字符没有正式的 URI 分隔用途,也可以安全地使用以下内容:

使用 MDN Web Docs 功能...

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}
5赞 Kamil Kiełczewski 6/12/2020 #18

性能

今天(2020.06.12)我在Chrome 83.0、Safari 13.1和Firefox 77.0浏览器上的macOS v10.13.6(High Sierra)上对选定的解决方案进行了速度测试。此结果对于海量 URL 编码非常有用。

结论

  • encodeURI(B) 似乎是最快的,但不建议用于 URL
  • escape(A) 是一种快速的跨浏览器解决方案
  • MDN 推荐的解决方案 F 为中等速度
  • 解决方案 D 最慢

Enter image description here

对于解决方案 A、B、C、D、E F,I 执行两个测试

  • 对于短 URL - 50 个字符 - 您可以在这里运行
  • 对于长 URL - 1M 字符 - 您可以在这里运行

function A(url) {
    return escape(url);
}

function B(url) {
    return encodeURI(url);
}

function C(url) {
    return encodeURIComponent(url);
}

function D(url) {
    return new URLSearchParams({url}).toString();
}

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

function F(url) {
  return encodeURIComponent(url).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}



// ----------
// TEST
// ----------

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

[A,B,C,D,E,F]
  .forEach(f=> console.log(`${f.name} ?url=${f(myUrl).replace(/^url=/,'')}`));
This snippet only presents code of chosen solutions

Chrome 的示例结果

Enter image description here

1赞 gurpartap 8/19/2020 #19

不要忘记 /g 标志来替换所有编码的 ' '

var myOtherUrl = "http://example.com/index.html?url=" + encodeURIComponent(myUrl).replace(/%20/g,'+');
0赞 Pyzard 12/11/2020 #20

我总是用它来对 URL 进行编码。这是完全安全的,因为它将对每个字符进行编码,即使它不必编码。

function urlEncode(text) {
    let encoded = '';
    for (let char of text) {
        encoded += '%' + char.charCodeAt(0).toString(16);
    }
    return encoded;
}

评论

0赞 TheSavageTeddy 11/27/2022
尽管这不是标准(不会在 GET 请求中使用),但它对于编码任何字符(例如用于 Web 开发)很有用,但对于只有 1 个十六进制长度的字符,需要用 0 填充。此外,它应该是大写的。
17赞 m4heshd 7/1/2021 #21

我认为现在在 2022 年要真正安全,您应该始终考虑使用 URL() 接口构建您的 URL。它将为您完成大部分工作。所以来到你的代码,

const baseURL = 'http://example.com/index.html';

const myUrl = new URL(baseURL);
myUrl.searchParams.append('param', '1');
myUrl.searchParams.append('anotherParam', '2');

const myOtherUrl = new URL(baseURL);
myOtherUrl.searchParams.append('url', myUrl.href);

console.log(myUrl.href);
// Outputs: http://example.com/index.html?param=1&anotherParam=2
console.log(myOtherUrl.href);
// Outputs: http://example.com/index.html?url=http%3A%2F%2Fexample.com%2Findex.html%3Fparam%3D1%26anotherParam%3D2
console.log(myOtherUrl.searchParams.get('url'));
// Outputs: http://example.com/index.html?param=1&anotherParam=2

或。。。

const params = new URLSearchParams(myOtherUrl.search);

console.log(params.get('url'));
// Outputs: http://example.com/index.html?param=1&anotherParam=2

这样的事情是肯定不会失败的。

0赞 Upasana Chauhan 1/12/2023 #22

let name = `bbb`;
params = `name=${name}`;
var myOtherUrl = `http://example.com/index.html?url=${encodeURIComponent(params)}`;
console.log(myOtherUrl); 

现在在 ES6 中使用反引号对 url 进行编码

试试这个 - https://bbbootstrap.com/code/encode-url-javascript-26885283