关于base64:传参base64时的号变空格问题

15次阅读

共计 1696 个字符,预计需要花费 5 分钟才能阅读完成。

原创:扣钉日记(微信公众号 ID:codelogs),欢送分享,非公众号转载保留此申明。

问题产生

上上周,看到一位老哥找咱们组共事联调接口,不晓得是什么问题,两人坐一起搞了快 1 个小时,看起来如同有点简单。

忽然,老哥收回一声卧槽,” 我传参里的 + 号,到你这怎么变成了空格!”,这个声音很大,我显著的听到了,很快,我就大略 Get 到了他们的问题点。

我猜想他们遇到的问题大略如下:

  1. 咱们的接口协议上,都会将申请数据做一次 base64 编码,而后放到 data 参数上。
  2. 而后某些数据做 base64 编码后有+,如{"notes":"代码"}base64 编码为eyJub3RlcyI6IuS7o+eggSJ9Cg==
  3. 而后间接拼到 data 参数上,即data=eyJub3RlcyI6IuS7o+eggSJ9Cg==,组织成 http 申请收回。

如果写成等价的 curl,就是这样:

$ curl http://localhost:8080/send -d 'data=eyJub3RlcyI6IuS7o+eggSJ9Cg=='

写个测试接口调试下看看,如下:

这就是他们遇到的问题,+会变成空格,这个坑其实蛮容易踩到,我本人刚工作时就踩到过这个坑,也屡次看到或听到他人同踩此坑🤣

问题起因

这个问题和 urlencode 编码无关,urlencode 编码,一般来说,除字母、数字和 *.-_这些字节原样输入外,其它字节都会编码为 %XX(16 进制) 的模式。

但有一个特例,如下:

String enc = URLEncoder.encode("","UTF-8");
System.out.println(enc);   // 输入 + 号

String dec = URLDecoder.decode("+", "UTF-8");
System.out.println(dec);   // 输入空格

特例就是空格会被编码为 + 号,反之,+号会被解码为空格!

注:在新的 RFC 2396 标准中,空格其实也能够编码成 %20,而解码时,+号与 %20 都会被解码为空格。

回忆下面的场景,如果将带有 + 号的 base64 字符串,一成不变的封装到 data= 中,再发送给 Tomcat 等 Web 服务器,若 Tomcat 侧做一次 urldecode 解码,+是不是就变成空格了😁

而 Tomcat 的确会做 urldecode 解码这样的操作,当调用方的 Content-Type 为 application/x-www-form-urlencoded 时,这里晓得有这种操作即可,想理解细节可看看我写的这篇文章 由 x -www-form-urlencoded 引发的接口对接失败

解决问题

解决这种问题,次要有两种办法,如下:

  1. 调用方对参数做 urlencode 编码。

按标准来看,当 Content-Type 为 application/x-www-form-urlencoded 时,调用方是必须对参数名与参数值做 urlencode 的,java 实现如下:

String base64Str = Base64.getEncoder().encodeToString(data);
String requestStr = "data=" + URLEncoder.encode(base64Str, "UTF-8");

这里做了 urlencode 后,+会被编码为 %2B,再由服务端解码,就会变成原样的+ 号。

注:如果是应用 apache 的 HttpClient,可思考应用UrlEncodedFormEntity,它会主动做这个事件。

  1. 应用 urlsafe 版本的 base64。

一般的 base64 不能间接作为参数值,因为它可能蕴含 +/ 这两个 url 不平安的字符,所以 base64 有个变种叫 urlBase64,它将 +/ 替换成了 url 平安的-_,java 实现如下:

String urlBase64Str = Base64.getUrlEncoder().encodeToString(data);
String requestStr = "data=" + urlBase64Str;

对于 base64、urlencode 编码,之前也专门写过一篇文章,感兴趣可进一步浏览 hex,base64,urlencode 编码方案比照

正文完
 0