base64编码之去除特殊字符

           这些天h5需要做一个推广页面,需要客户端将地理位置信息以及用户的一些信息传递给h5页面,一般的话可以通过给h5注入对象,调用方法的方式来实现。但是想想这个页面是需要通过客户端生成二维码,别的用户用微信或者其他的二维码扫描工具扫描之后才出现的,所以不是通过自己客户端的webview来加载的,所以说这种方式不可行,那么就另外一种方式,就是在h5页面地址后面进行拼接,然后让h5取值,就是采用了这个方案。

           但是不管是用户的信息还是客户端取到的地理位置信息,都是用户的隐私信息,所以不能直接就通过?以及&的方式明文拼接在后面,要是通过微信扫描打开页面还好,看不到地址,但是如果是在浏览器中打开,那么地址就是一目了然了,那么用户信息岂不就是泄漏了么?所以还是稍微加密下吧,因为不想太麻烦,所以就直接采用Base64进行编码,其实也不属于加密。那么方案有了,接下来就是实施了。

           其实之前也用Base64转过字符串,不过那时候是将一张图片通过base64转换为字符串传递给服务端了,以前总是用那个sun.misc.BASE64Decoder.jar了,其实android里面里面已经自带了的base64工具类,所以这次我们用这个方法吧。它有encodeToString方法,如果不需要特殊处理,那么第二个参数直接传递Base64.DEFAULT就好了。我们可以试一下:对字符串String param = “北京市哈哈取某某门门南大街靠近值招商银行(北二环支行)&province=北京市&city=北京市&area=某某区&country=中国&street=哈哈门西大街&aaid=000000&time=1505370170813”进行base64编码。android自带的Base64.encodeToString方法,即为Base64.encodeToString(param.getBytes(),Base64.DEFAULT)我们得到的结果为:                                              

 5YyX5Lqs5biC5ZOI5ZOI5Y+W5p+Q5p+Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L+R5YC85oub5ZWG6ZO2
 6KGMKOWMl+S6jOeOr+aUr+ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFy
 ZWE95p+Q5p+Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb/lpKfooZcmYWFp
 ZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz

是的,它换行了,因为我们是让h5同学去解编码的,让h5同学一看,当时就懵了,直接就不能解,为什么会换行呢?那是因为默认模式下,编码后的如果长度超过76,那么每逢76个字符就会加一个换行符。前面我们看到encodeToString有两个参数,那就看看第二个参数还有别的什么值吧,可以看到注释如下:

/**
     * Default values for encoder/decoder flags.
     */
    public static final int DEFAULT = 0;

    /**
     * Encoder flag bit to omit the padding '=' characters at the end
     * of the output (if any).
     */
    public static final int NO_PADDING = 1;

    /**
     * Encoder flag bit to omit all line terminators (i.e., the output
     * will be on one long line).
     */
    public static final int NO_WRAP = 2;

    /**
     * Encoder flag bit to indicate lines should be terminated with a
     * CRLF pair instead of just an LF.  Has no effect if {@code
     * NO_WRAP} is specified as well.
     */
    public static final int CRLF = 4;

    /**
     * Encoder/decoder flag bit to indicate using the "URL and
     * filename safe" variant of Base64 (see RFC 3548 section 4) where
     * {@code -} and {@code _} are used in place of {@code +} and
     * {@code /}.
     */
    public static final int URL_SAFE = 8;

    /**
     * Flag to pass to {@link Base64OutputStream} to indicate that it
     * should not close the output stream it is wrapping when it
     * itself is closed.
     */
    public static final int NO_CLOSE = 16;
可以看到第二个参数有6种情况,第一种就是默认,我们刚刚试了。如果要解决换行问题,那么得用NO_WRAP了,因为它的意思就是会将所有字符输出至一行,所以我们换成Base64.encodeToString(param.getBytes(),Base64.NO_WRAP),输出结果如下:5YyX5Lqs5biC5ZOI5ZOI5Y+W5p+Q5p+Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L+R5YC85oub5ZWG6ZO26KGMKOWMl+S6jOeOr+aUr+ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFyZWE95p+Q5p+Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb/lpKfooZcmYWFpZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz;对,这次没有换行, 貌似是我们想要的呢,假装我们拼接后生成二维码背后的地址就是https://www.baidu.com?param=5YyX5Lqs5biC5ZOI5ZOI5Y+W5p+Q5p+Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L+R5YC85oub5ZWG6ZO26KGMKOWMl+S6jOeOr+aUr+ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFyZWE95p+Q5p+Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb/lpKfooZcmYWFpZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz;好的用微信扫描该地址生成的二维码可以出来页面,但是我们的页面还有引导用户下载我们apk的功能,但是微信里面是不支持下载的,故而必须提示用户在浏览器中打开,所以最终这个地址是需要在浏览了器中打开,那我们可以将其生成二维码,然后用微信扫描后再次在手机浏览器中打开试试(一定得是手机浏览器中哦),可是地址变成了下面酱紫:https://www.baidu.com/?param=5YyX5Lqs5biC5ZOI5ZOI5Y%20W5p%20Q5p%20Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L%20R5YC85oub5ZWG6ZO26KGMKOWMl%20S6jOeOr%20aUr%20ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFyZWE95p%20Q5p%20Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb%2FlpKfooZcmYWFpZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz;可以看到跟上面相比所有的+以及斜杠都转义成了%,那这后面一串让h5去解肯定会失败,那就看看其他的参数;突然发现URL_SAFE这个意思是能够将编码后的+以及/转换成-以_了,貌似符合我们个预期,我们试试,最终结果如下:

5YyX5Lqs5biC5ZOI5ZOI5Y-W5p-Q5p-Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L-R5YC85oub5ZWG6ZO2
6KGMKOWMl-S6jOeOr-aUr-ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFy
ZWE95p-Q5p-Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb_lpKfooZcmYWFp
ZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz

的确那些加号以及斜杠被替换了,可是又换行了呀,所以在想如果有一个属性能够同时实现URL_SAFE和NO_WRAP就好了呢,可是属性就那么6个,没有一个能够达到这种效果,可以看到后面第二个参数其实是一个常量,其实之前这样写过,view.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM)就是希望该view在其父布局的底部且水平方向居中。那么encodeToString方法是否可以这样子写呢,试了下,答案是可以的,哈哈。所以现在可以酱紫写 Base64.encodeToString(param.getBytes(),Base64.URL_SAFE|Base64.NO_WRAP)),我们的得到的结果是什么呢?结果如下:5YyX5Lqs5biC5ZOI5ZOI5Y-W5p-Q5p-Q6Zeo6Zeo5Y2X5aSn6KGX6Z2g6L-R5YC85oub5ZWG6ZO26KGMKOWMl-S6jOeOr-aUr-ihjCkmcHJvdmluY2U95YyX5Lqs5biCJmNpdHk95YyX5Lqs5biCJmFyZWE95p-Q5p-Q5Yy6JmNvdW50cnk95Lit5Zu9JnN0cmVldD3lk4jlk4jpl6jopb_lpKfooZcmYWFpZD0wMDAwMDAmdGltZT0xNTA1MzcwMTcwODEz;嗯,这次没有换行且没有特殊字符了,终于满足我们的预期。其实还有最后一点,在有些定位地址下,编码后的字符串最后几位会出现=,而=在浏览器里面打开也是有问题的,所以也需要替换掉,此时可以用上面的NO_PADDING,它的意思就是在最后会省略填充=。那么最终我们的方式是这样子的:Base64.encodeToString(param.getBytes(),Base64.URL_SAFE|Base64.NO_WRAP|Base64.NO_PADDING)的。如果不是非要在浏览器中打开,其实是不用这么费事的。

        好了,以上就是本次文章的所有内容。如果不对之处,欢迎批评指正。


你可能感兴趣的:(android小日子记录,Base64编码,Base64特殊字符处理,Base64中文乱码)