很多网络协议中都会提到一系列步骤,如DNS解析、建立连接、发送HTTP请求、接收HTTP响应、渲染网页等。然而,今天我想在这些步骤之前插入一个新的步骤:URL解析。URL(统一资源定位符)由四部分组成:scheme、domain、path和resource。
URL解析主要包括两个步骤:解析URL并分离出domain,以及后续的DNS解析。此外,还有一个重要的话题是URL编码。
本文将重点讨论URL编码。
- 为什么需要URL编码?
- JavaScript中的encodeURI()和encodeURIComponent()的区别
- 我为什么对这个问题感兴趣?
- 常见的HTTP客户端是否默认进行URL编码?
在浏览器中输入
https://www.baidu.com/s?wd=博客园马甲哥
,在按下Enter键之前,你可以尝试复制地址栏的内容,然后粘贴到其他地方,你会发现内容变成了
https://www.baidu.com/s?wd=%E5%8D%9A%E5%AE%A2%E5%9B%AD%E9%A9%AC%E7%94%B2%E5%93%A5
,这就是浏览器自动进行URL编码的结果。浏览器会使用这个网址进行DNS解析和发起请求。
1. 为什么需要URL编码?
URL编码,又称百分号编码,是为了确保URI地址最初要求以可显示、可写的ASCII字符集表示。非英文字符和其他特殊字符需要被编码。默认情况下,按照UTF-8转化为字节流,每个字节按16进制表示,并添加%组成一个percent编码。
例如:汉字“你好”
- UTF-8字节流打印为:-28 -67 -96 -27 -91 -67
- 对应的16进制表示为:E4 BD A0 E5 A5 BD
- URLEncode编译后为:%E4%BD%A0%E5%A5%BD
当然,服务端会有相应的
url_decode
函数,编码/解码的次数需要对应。
2. JavaScript中的encodeURI() vs encodeURIComponent()
encodeURI是JavaScript中的内置全局函数,用于URL编码,不会对特殊字符进行编码,这样可以确保URL中原生字符的正确表达。
const uri = 'https://mozilla.org/?x=шеллы';
const encoded = encodeURI(uri);
console.log(encoded);
// 期望输出: "https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"
encodeURIComponent也是全局函数,但它的作用是对字符串进行完整的URL编码,该函数会对上述排除的字符进行编码,通常用于已知需要进行URL编码的特殊字符。
// 对字符进行编码,例如 ?、=、/、&、:
console.log(`?x=${encodeURIComponent('test?')}`);
// 期望输出: "?x=test%3F"
3. 我为什么对这个问题感兴趣?
通常情况下,Web框架会自动进行解码,因此在直接处理HTTP请求时,我们可以忽略这个问题。但是,在使用HTTP客户端进行反向代理时,就需要注意这个问题。
我在使用lua-resty-http客户端进行反向代理请求时遇到了这个问题。一开始,lua_resty_http将解码后的$uri传递给应用,与应用的预期不符,因此需要将其恢复为原始编码的URI。
4. 常见的HTTP客户端是否默认进行URL编码?
.NET、Go、Lua的HttpClient(包括curl)都不会自动对URL进行编码。如果URL包含特殊字符或需要编码的字符,你需要手动进行URL编码。
- [C#] System.Net.WebUtility.UrlEncode
- [Go] url.QueryEscape(rawURL)
- [Lua] ngx.escape_uri(str, 0)
标签:游戏攻略