您如何使用 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
参数,您应该使用 escape
或 encodeURIComponent
,而不是 encodeURI
。
有关进一步讨论,请参阅 Stack Overflow 问题Best practice: escape, or encodeURI / encodeURIComponent。
%uxxx
。
坚持使用 encodeURIComponent()
。函数 encodeURI()
不会费心编码许多在 URL 中具有语义重要性的字符(例如“#”、“?”和“&”)。 escape()
已弃用,并且不费心对“+”字符进行编码,这将被解释为服务器上的编码空格(并且,正如其他人在此处指出的那样,不会正确地对非 ASCII 字符进行 URL 编码)。
其他地方有一个不错的explanation of the difference between encodeURI()
and encodeURIComponent()
。如果您想对某些内容进行编码,以便可以安全地将其作为 URI 的一个组件包含在内(例如,作为查询字符串参数),您需要使用 encodeURIComponent()
。
最好的答案是在查询字符串中的 values 上使用 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}`;
http://somedomain/this dir has spaces/info.php?a=this has also spaces
。它应转换为:http://somedomain/this%20dir%20has%spaces/info.php?a=this%20has%20also%20spaces
,但许多实现允许将查询字符串中的 '%20' 替换为 '+'。但是,您不能在 URL 的路径部分将 '%20' 替换为 '+',这将导致 Not Found 错误,除非您的目录带有 +
而不是空格。
encodeURIComponent('+')
会给你 %2B
,所以你必须使用两个正则表达式......我想这就是为什么这样做,因为 '+' 是 ' ' 最后编码不同。
我建议使用 qs npm package
qs.stringify({a:"1=2", b:"Test 1"}); // gets a=1%3D2&b=Test+1
它更容易与 JS 对象一起使用,它为所有参数提供了正确的 URL 编码
如果您使用的是 jQuery,我会选择 $.param
方法。它的 URL 将对象映射字段编码为值,这比对每个值调用转义方法更容易阅读。
$.param({a:"1=2", b:"Test 1"}) // gets a=1%3D2&b=Test+1
现代解决方案 (2021)
由于编写了其他答案,因此引入了 URLSearchParams API。它可以这样使用:
const queryParams = { param1: 'value1', param2: 'value2' }
const queryString = new URLSearchParams(queryParams).toString()
// 'param1=value1¶m2=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() 是要走的路。
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() 的理由——我会把它留给更聪明的人。
我认为现在在 2022 年非常安全,您应该始终考虑使用 URL()
interface 构建您的 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
这样的事情保证不会失败。
我用普通的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"
什么是 URL 编码:
当 URL 中存在特殊字符时,应该对 URL 进行编码。例如:
console.log(encodeURIComponent('?notEncoded=&+'));
我们可以在这个例子中观察到,除了字符串 notEncoded
之外的所有字符都用 % 符号编码。 URL 编码也称为百分比编码,因为它使用 % 转义所有特殊字符。然后在这个 % 符号之后,每个特殊字符都有一个唯一的代码
为什么我们需要 URL 编码:
某些字符在 URL 字符串中具有特殊值。例如,?字符表示查询字符串的开始。为了在网络上成功定位资源,必须区分字符是作为字符串的一部分还是作为 url 结构的一部分。
我们如何在 JS 中实现 URL 编码:
JS 提供了一系列内置实用程序函数,我们可以使用它们轻松地对 URL 进行编码。这是两个方便的选项:
encodeURIComponent():将 URI 的一个组件作为参数,并返回编码后的 URI 字符串。 encodeURI():将 URI 作为参数并返回编码后的 URI 字符串。
示例和注意事项:
请注意不要将整个 URL(包括方案,例如 https://)传递到 encodeURIComponent()
。这实际上可以将其转换为无效的 URL。例如:
// 对于整个 URI,不要使用 encodeURIComponent,它会转换 // 字符和 URL 将无法正常运行 console.log(encodeURIComponent("http://www.random.com/specials&char.html")) ; // 而是对整个 URL 使用 encodeURI console.log(encodeURI("http://www.random.com/specials&char.html"));
我们可以观察到,如果我们将整个 URL 放在 encodeURIComponent
中,正斜杠 (/) 也被转换为特殊字符。这将导致 URL 不再正常工作。
因此(顾名思义)使用:
在要编码的 URL 的某个部分上进行 encodeURIComponent。在要编码的整个 URL 上进行 encodeURI。
您不应直接使用 encodeURIComponent()
。
Take a look at RFC3986: Uniform Resource Identifier (URI): Generic Syntax
子分隔符=“!” /“$”/“&”/“'”/“(”/“)”/“*”/“+”/“”/“;” / "=" 保留字符的目的是提供一组分隔字符,可与 URI 中的其他数据区分开来。
RFC3986 中 URI 定义中的这些保留字符不会被 encodeURIComponent()
转义。
MDN Web Docs: encodeURIComponent()
为了更加严格地遵守 RFC 3986(保留 !、'、(、) 和 *),即使这些字符没有正式的 URI 定界用途,也可以安全地使用以下内容:
使用 MDN Web Docs 功能...
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
没有什么对我有用。我所看到的只是登录页面的 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;
}
}
});
});
现在我没有任何问题,它就像一个魅力。
编码 URL 字符串
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
这是 encodeURIComponent()
和 decodeURIComponent()
JS 内置函数的 LIVE DEMO:
<!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>
表现
今天(2020.06.12)我在浏览器 Chrome 83.0、Safari 13.1、Firefox 77.0 上对 MacOs HighSierra 10.13.6 上的所选解决方案进行速度测试。此结果可用于大量 url 编码。
结论
encodeURI (B) 似乎最快,但不推荐用于 url-s
escape (A) 是快速跨浏览器解决方案
MDN推荐的解决方案F是中快
解决方案 D 最慢
https://i.stack.imgur.com/Z9Xjl.png
细节
对于短 url - 50 char - 你可以在这里运行它
对于长 url - 1M char - 你可以在这里运行它
函数 A(url) { 返回转义(url); } 函数 B(url) { 返回 encodeURI(url); } 函数 C(url) { 返回 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); }) ; } // ---------- // 测试 // ---------- 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=/,'' )}`));此代码段仅显示所选解决方案的代码
Chrome 的示例结果
https://i.stack.imgur.com/HBWv9.png
您可以使用 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;
}
https://www.owasp.org/index.php/ESAPI_JavaScript_Readme
使用fixedEncodeURIComponent
函数严格遵守RFC 3986:
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
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;
}
不定期副业成功案例分享
escape
也是一个有效选项。encodeURI
对于 URL 编码来说并不是很安全。:
、/
、@
等字符。这两种方法不能互换使用,你必须知道你在编码什么使用正确的方法。