阿拉伯语的okhttp兼容问题

发布于:2025-06-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

背景是最近测试在测阿拉伯语言的时候,okhttp抛出了异常,异常信息如下:

java.lang.IllegalArgumentException: Unexpected char 0x665 at 0 in ScreenSize value: ٥٫٧٥

okhttp3.Headers 中抛出的,代码见:

private fun checkValue(value: String, name: String) {
    for (i in value.indices) {
    val c = value[i]
    require(c == '\t' || c in '\u0020'..'\u007e') {
        format("Unexpected char %#04x at %d in %s value", c.toInt(), i, name) +
            (if (isSensitiveHeader(name)) "" else ": $value")
    }
    }
}

okhttp 的Issue上有人反馈这个问题

https://github.com/square/okhttp/issues/2802
Strictly speaking this is a problem with Facebook’s NetworkingModule.java. The fix is a method like so:

/** Returns {@code s} with control characters and non-ASCII characters replaced with '?'. */
public static String toHumanReadableAscii(String s) {
for (int i = 0, length = s.length(), c; i < length; i += Character.charCount(c)) {
    c = s.codePointAt(i);
    if (c > '\u001f' && c < '\u007f') continue;

    Buffer buffer = new Buffer();
    buffer.writeUtf8(s, 0, i);
    for (int j = i; j < length; j += Character.charCount(c)) {
    c = s.codePointAt(j);
    buffer.writeUtf8CodePoint(c > '\u001f' && c < '\u007f' ? c : '?');
    }
    return buffer.readUtf8();
}
return s;
}

修改方法

var number = 5.75F
// 有问题的序列化,٥٫٧٥
val string = DecimalFormat("0.00").format(number)
// 正常序列化
String.format(Locale.ENGLISH, "%.2f",number)

原因

在OkHttp的Request.Builder的addHeader方法中,添加一个包含非ASCII字符(如阿拉伯数字)的值,实际上是可以直接添加的,因为HTTP头部允许使用UTF-8编码的字符。

但是,根据HTTP规范,头部字段值应该是ASCII字符,但实践中,许多服务器和客户端已经支持UTF-8编码的头部值。不过,为了最大兼容性,通常建议对非ASCII字符进行编码或转换为ASCII兼容的表示。

如果你控制服务器和客户端,并且可以确保双方都支持UTF-8,那么直接添加应该没有问题。但如果你遇到接收方无法解析的情况(比如接收方使用的是只支持ASCII的解析方法),那么你需要将值转换为ASCII数字和点号。

因此,在添加头部之前,将字符串中的非ASCII数字和符号替换为ASCII字符: