背景是最近测试在测阿拉伯语言的时候,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字符: