• 传参base64时的+号变空格问题


    原创:扣钉日记(微信公众号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=='
    

    写个测试接口调试下看看,如下:
    bug
    这就是他们遇到的问题,+会变成空格,这个坑其实蛮容易踩到,我自己刚工作时就踩到过这个坑,也多次看到或听到别人同踩此坑🤣

    问题原因#

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

    但有一个特例,如下:

    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编码方案对比

  • 相关阅读:
    Java集合之Map
    立方体IV(暑假每日一题 10)
    解释器模式 行为型模式之五
    前端面试题目小结 之一(精选10题)
    狂神说Java之 rabbitmq高级分布式事务
    Redis key(BigKey、MoreKey)的存储策略
    基于Jeecgboot前后端分离的ERP系统开发代码生成(一)
    【推送服务】【FAQ】Push Ki常见咨询合集6--消息报表类问题
    Multi-scalar multiplication: state of the art & new ideas
    四入进博会,优衣库围绕科技可持续演绎“服装进化论”
  • 原文地址:https://www.cnblogs.com/codelogs/p/17255425.html