一、URL中的特殊字符及其对应的编码
网址URL中特殊字符转义编码
字符 - URL编码值
空格 - %20
" - %22
# - %23
% - %25
& - %26
( - %28
) - %29
+ - %2B
, - %2C
/ - %2F
: - %3A
; - %3B
< - %3C
= - %3D
> - %3E
? - %3F
@ - %40
\ - %5C
| - %7C
URL特殊字符转义,URL中一些字符的特殊含义,基本编码规则如下:
1、空格换成加号(+)
2、正斜杠(/)分隔目录和子目录
3、问号(?)分隔URL和查询
4、百分号(%)制定特殊字符
5、#号指定书签
6、&号分隔参数
如果需要在URL中用到,需要将这些特殊字符换成相应的十六进制的值
+ %2B
/ %2F
? %3F
% %25
# %23
& %26
二、为什么需要Url编码
一样东西需要编码的原因有很多,但通常可能是Size过大,包含隐私数据等。对于Url来说要进行编码的原因是Url中有些字符会引起歧义。例如Url参数字符串中使用key=value键值对这样的形式来传参,键值对之间以&符号分隔,如“myVideo.mp4?t=5a71afc0&rlimit=3&us=72d4cd1101”(QueryString方式)。如果你的value字符串中包含了=或者&,那么势必会造成接收Url的服务器解析错误,因此必须将引起歧义的&和= 符号进行转义,也就是对其进行编码。
http://example.vod2.myqcloud.com/dir1/dir2/myVideo.mp4?t=5a71afc0&rlimit=3&us=72d4cd1101&sign=c5214f0d5df
又如,Url的编码格式采用的是ASCII码,而不是Unicode,这也就是说你不能在Url中包含任何非ASCII字符,例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下,中文可能会造成问题。
url编码的原则就是使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。
哪些字符需要编码
RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。
RFC3986文档对Url的编解码问题做出了详细的建议,指出了哪些字符需要被编码才不会引起Url语义的转变,以及对为什么这些字符需要编码做出了相应的解释。
US-ASCII字符集中没有对应的可打印字符
Url中只允许使用可打印字符。US-ASCII码中的10-7F字节全都表示控制字符,这些字符都不能直接出现在Url中。同时,对于80-FF字节(ISO-8859-1),由于已经超出了US-ACII定义的字节范围,因此也不可以放在Url中。
保留字符
Url可以划分成若干个组件,协议、主机、路径等。有一些字符(:/?#[]@)是用作分隔不同组件的。例如:冒号用于分隔协议和主机,/用于分隔 主机和路径,?用于分隔路径和查询参数,等等。还有一些字符(!$&'()*+,;=)用于在每个组件中起到分隔作用的,如=用于表示查询参数中 的键值对,&符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进行编码。
三、C++代码的实现
#include<iostream>
#include <string>
using namespace std;
static std::string UrlEncode(const std::string& in_url)
{
const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}/,";
const char hex[] = "0123456789ABCDEF";
int len = in_url.size();
std::string out_url;
out_url.reserve(len + len);
for (int i = 0; i < len; ++i)
{
char c = in_url[i];
if (c < ' ' || c > '~' || strchr(urlunsafe, c))
{
out_url += '%';
out_url += char(hex[(c >> 4) & 0x0f]);
out_url += char(hex[c & 0x0f]);
}
else
{
out_url += c;
}
}
return out_url;
}
std::string UrlDecode(const std::string& in_url)
{
int len = in_url.size();
std::string out_url;
out_url.reserve(len);
const char* p = in_url.data();
for (int i = 0; i < len; ++i)
{
unsigned int tmp = 0;
char c = in_url[i];
if ((c == '%') && (i + 2 < len) && (sscanf(p + i + 1, "%2x", &tmp) == 1))
{
out_url += (char)tmp;
i += 2;
}
else
{
out_url += c;
}
}
return out_url;
}
int main(){
std::string str;
cout << "Please input a string:";
cin >> str;
cout << "raw str is : " << str << endl;
str = UrlEncode(str);
cout << "do urlencode:" << str << endl;
str = UrlDecode(str);
cout << "do urldecode:" << str << endl;
}
效果如下: