在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变量?

1798379 次浏览

查看内置函数//组件名//组件名请求编码URI(str)
在你的情况下,这应该工作:

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

你有三个选择:

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

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

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

但在您的情况下,如果您想将url传递给其他页面的GET参数,您应该使用escapeencodeURIComponent,而不是encodeURI

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

坚持#0。函数#1不会费心编码许多在URL中具有语义重要性的字符(例如. "#", "?", 和“&”)。#2已弃用,并且不会费心编码“+”字符,这将被解释为服务器上的编码空格(并且,正如其他人在这里指出的,不会正确地URL编码非ASCII字符)。

在其他地方有一个很好的解释#0和#1之间的区别。如果您想对某物进行编码,以便它可以安全地包含为URI的组件(例如作为查询字符串参数),您需要使用encodeURIComponent()

我所看到的只是登录页面的超文本标记语言,返回到客户端的代码为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;}}});});

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

最好的答案是在查询字符串中的上使用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 replaceconst url = `http://example.com/${escapedFolder}/?myKey=${escapedValue}`;

建议使用qs npm包

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

它更容易与JS对象一起使用,它为所有参数提供正确的URL编码

如果您使用jQuery,我会选择#0方法。它将URL编码为对象映射字段到值,这比对每个值调用转义方法更容易阅读。

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

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

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

编码URL字符串

var url = $(location).attr('href'); //get current url//ORvar 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 for more info go http://www.sitepoint.com/jquery-decode-url-string

codeURIComponent()是要走的路。

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

但是你应该记住,与php版本urlencode()有一些小的区别,正如@CMS提到的,它不会编码每个char。http://phpjs.org/functions/urlencode/的人制作了相当于phpencode()的js:

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', '+');}

您可以使用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;}

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

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

encodeURI("abc%20xyz 123")            //   Wrong: "abc%2520xyz%20123"encodeURI(decodeURI("abc%20xyz 123")) // Correct: "abc%20xyz%20123"

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

encodeURI()

encodeURIComponent()

两者都存在的原因是,第一个保留了URL,有可能留下太多未转义的内容,而第二个对所需的一切进行编码。

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

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

因此,如果您可以花时间,您总是希望在添加名称/值对之前使用该函数对名称和值进行编码,然后再将其添加到查询字符串中。

我一直在苦苦思索着如何使用codeURI()——我将把它留给更聪明的人。

什么是URL编码:

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

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

We can observe in this example that all characters except the string notEncoded are encoded with % signs. URL encoding is also known as percentage encoding because it escapes all special characters with a %. Then after this % sign every special character has a unique code

Why do we need URL encoding:

Certain characters have a special value in a URL string. For example, the ? character denotes the beginning of a query string. In order to succesfully locate a resource on the web, it is necesarry to distinguish between when a character is meant as a part of string or part of the url structure.

How can we achieve URL encoding in JS:

JS offers a bunch of build in utility function which we can use to easily encode URL's. These are two convenient options:

  1. encodeURIComponent(): Takes a component of a URI as an argument and returns the encoded URI string.
  2. encodeURI(): Takes a URI as an argument and returns the encoded URI string.

Example and caveats:

Be aware of not passing in the whole URL (including scheme, e.g https://) into encodeURIComponent(). This can actually transform it into a not functional URL. For example:

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

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

因此(顾名思义)使用:

  1. encodeURIComponent在您要编码的URL的某个部分上。
  2. encodeURI在您要编码的整个URL上。

这是encodeURIComponent()decodeURIComponent() JavaScript内置函数中的现场演示

<!DOCTYPE html><html><head><style>textarea{width: 30%;height: 100px;}</style><script>// Encode string to Base64function encode(){var txt = document.getElementById("txt1").value;var result = btoa(txt);document.getElementById("txt2").value = result;}// Decode Base64 back to original stringfunction 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>

使用fixedEncodeURIComponent函数严格遵守rfc3986

function fixedEncodeURIComponent(str) {return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {return '%' + c.charCodeAt(0).toString(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());

这个解决方案也被提到这里这里

您不应该直接使用encodeURIComponent()

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

子分隔符="!"/"$"/"&"/"'"/"("/")"/"*"/"+"/","/";"/"="

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

RFC3986中URI定义中的这些保留字符不会被encodeURIComponent()转义。

MDN Web Docs: codeURIComponent()

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

使用MDN Web Docs函数…

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

性能

今天(2020.06.12)我在浏览器Chrome83.0、Safari13.1、Firefox 77.0上对MacO HighSierra 10.13.6上的所选解决方案进行速度测试。此结果可用于大量URL编码。

结论

  • encodeURI(B)似乎最快,但不是推荐用于url-s
  • escape(A)是快速的跨浏览器解决方案
  • MDN推荐的解决方案F是中速
  • D是最慢的

在此处输入图片描述

详情

解决方案ABCDEF我做了两个测试

  • 对于短url-50 char-你可以运行它这里
  • 对于long url-1Mchar-你可以运行它这里

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 choosen solutions

Example results for Chrome

enter image description here

var myOtherUrl ="http://example.com/index.html?url=" + encodeURIComponent(myUrl).replace(/%20/g,'+');

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

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

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

我认为现在在2022年要真正安全,你应该始终考虑使用#0接口构建你的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=2console.log(myOtherUrl.href);// Outputs: http://example.com/index.html?url=http%3A%2F%2Fexample.com%2Findex.html%3Fparam%3D1%26anotherParam%3D2console.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

这样的事情保证不会失败。