okhttp addHeader 字符串中含有中文引起的Crash

最近项目中的网络框架由AsyncHttp切换成了OKHttp,改动比较大,经过测试上线后,也确实担心会出问题,查看Bugly Crash记录,真是怕什么来什么……

出现了异常:

java.lang.IllegalArgumentException

Unexpected char 0x3000 at 35 in User-Agent value: Mozilla/5.0 (Linux; Android 5.0.2;    Build/DBXCNOP5501001303S) AppleWebKit/537.36 (KHTML, like Gecko)   Version/4.0 Chrome/37.0.0.0 Mobile Safari/537.36

java.lang.IllegalArgumentException

Unexpected char 0x950b at 35 in User-Agent value: Mozilla/5.0 (Linux; Android 4.4.4; 锋尚MAX Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36

异常最终是抛在了Headers中的checkNameAndValue,OKHttp 设置请求头时,是不支持换行和中文字符的,在添加头时会做Header的Key和Value的检查,如果发现非法字符则抛出上述异常。

private void checkNameAndValue(String name, String value) {
  if (name == null) throw new IllegalArgumentException("name == null");
  if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
  for (int i = 0, length = name.length(); i < length; i++) {
    char c = name.charAt(i);
    if (c <= '\u001f' || c >= '\u007f') {
      throw new IllegalArgumentException(String.format(
          "Unexpected char %#04x at %d in header name: %s", (int) c, i, name));
    }
  }
  if (value == null) throw new IllegalArgumentException("value == null");
  for (int i = 0, length = value.length(); i < length; i++) {
    char c = value.charAt(i);
    if (c <= '\u001f' || c >= '\u007f') {
      throw new IllegalArgumentException(String.format(
          "Unexpected char %#04x at %d in %s value: %s", (int) c, i, name, value));
    }
  }
}

因为服务端要统计一些信息,所以约定每个请求都需要上传UA。添加UA是通过实现NetworkInterceptor 网络拦截器实现每个请求都带有UA的,国产手机厂商会把手机型号加到UA里,也许是为了统计吧,之前的AsyncHttp没有这个问题,测试设备中也并未有ua带中文的测试机,这个问题被忽略掉,吐血…… 第一个异常是因为用了全角的空格,全角的空格Unicode码是\u3000。

解决方案:

因为UA服务端需要做统计,所以不能直接使用Base64编码,服务端没有解码逻辑需要对获取到的UA做合法性校验,遇到不符合条件的字符就过滤掉,过滤掉这些字符对统计应该不会有什么影响。

private static String getValidUA(String userAgent){
    StringBuffer sb = new StringBuffer();
    for (int i = 0, length = userAgent.length(); i < length; i++) {
        char c = userAgent.charAt(i);
        if (!(c <= '\u001f' || c >= '\u007f')) {
           sb.append(c);
        }
    }
    return sb.toString();
}
在网上看到另外两种方案,也是可行的。

法1:检测为不合法字符,就转为unicode 编码,OkHttp 中的checkNameAndValue去遍历每个字符就不会为非法了

private static String getValidUA(String userAgent){
    StringBuffer sb = new StringBuffer();
    for (int i = 0, length = userAgent.length(); i < length; i++) {
        char c = userAgent.charAt(i);
        if (c <= '\u001f' || c >= '\u007f') {
            sb.append(String.format("\\u%04x", (int) c));
        } else {
            sb.append(c);
        }
    }
    return sb.toString();
}

法2:如果发现非法字符,采用UrlEncode对其进行编码

private String getValidUA(String userAgent){
    if(TextUtils.isEmpty(userAgent)){
        return "android";
    }
    String validUA = "android";
    String uaWithoutLine = userAgent.replace("\n", "");
    for (int i = 0, length = uaWithoutLine.length(); i < length; i++){
        char c = userAgent.charAt(i);
        if (c <= '\u001f' || c >= '\u007f') {
            try {
                validUA = URLEncoder.encode(uaWithoutLine, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return validUA;
        }
    }
    return uaWithoutLine;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值