前言
我们有时候需要在GET的参数中传递参数,例如是byte[]类型的内容,一般来说是转成Base64的编码格式,但是带来一个问题是:base64编码后,里面可能会出现一些字符是url里面冲突的,例如=+/这些,虽然可以URLEncode进行编码,但这还是会给程序带来一些复杂度或者不确定性。
URL编码规范
关于URL编码的详细规范,可以查看RFC 3986, 这里只对我们会涉及的信息做简要说明。
RFC 3986中有如下两个重要规定:
- Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、
-
_
.
~
4个特殊字符以及所有保留字符。 - 保留字符包括:
!
*
'
(
)
;
:
@
&
=
+
$
,
/
?
#
[
]
另外,还有很多字符,当它们直接放在Url中的时候,可能会引起解析程序的歧义。
这些字符被视为不安全字符,原因有很多。
- 空格:Url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉;
- 引号以及<>:引号和尖括号通常用于在普通文本中起到分隔Url的作用;
- #:通常用于表示书签或者锚点;
- %:百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码;
{
}
|
\
^
[
]
`
~
:某一些网关或者传输代理会篡改这些字符。
url安全的base64编码
在实际的应用中,url参数的字符串是一个base64编码的json字符串,这就可能出现不符合url编码规范的结果, 因为base64编码会出现+
,/
,=
这些被url转码的特殊字符,一旦这个结果被转码了,第三方应用获取到的base64字符串和服务端 签名生成的就不一致了,因此对它编码必须是url安全的base64编码。
url安全的base64编码规范一般采用如下方式:
- 将base64中的
+
号换成-
号 - 将base64中的
/
号换成_
号 - 将base64中的
=
号换成空字符串,即删除=
号
对应的,url安全的base64解码过程要反过来:
- 将base64中的
-
号换成+
号 - 将base64中的
_
号换成/
号 - 在base64中末位补齐
=
号,使得base64的字符数量可以被4整除
java编码示例代码如下:
public static String safeUrlBase64Encode(byte[] data) { String encodeBase64 = new String(Base64.getEncoder().encode(data)); String safeBase64Str = encodeBase64.replace('+', '-'); safeBase64Str = safeBase64Str.replace('/', '_'); safeBase64Str = safeBase64Str.replaceAll("=", ""); return safeBase64Str; }
java解码示例代码如下:
public static byte[] safeUrlBase64Decode(final String safeBase64Str) { String base64Str = safeBase64Str.replace('-', '+'); base64Str = base64Str.replace('_', '/'); int mod4 = base64Str.length() % 4; if (mod4 > 0) { base64Str = base64Str + "====".substring(mod4); } return Base64.getDecoder().decode(base64Str); }
文章评论