在 url 参数中发送十六进制字符串并尝试在服务器端将其转换为字符串。 使用以下 javascript 编码代码转换用户输入的字符串
function encode(string) {
var number = "";
var length = string.trim().length;
string = string.trim();
for (var i = 0; i < length; i++) {
number += string.charCodeAt(i).toString(16);
}
return number;
}
现在我正在尝试在java代码中解析十六进制字符串
419
为俄语字符Й
,如下
byte[] bytes = "".getBytes();
try {
bytes = Hex.decodeHex(hex.toCharArray());
sb.append(new String(bytes,"UTF-8"));
} catch (DecoderException e) {
e.printStackTrace(); // Here it gives error 'Odd number of characters'
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
但它给出以下错误
"org.apache.commons.codec.DecoderException: Odd number of characters."
如何解决。由于许多俄语字符具有 3 位十六进制代码,因此无法将其转换为
.toCharArray()
。
改用 Base64
val aes = KeyGenerator.getInstance("AES")
aes.init(128)
val secretKeySpec = aes.generateKey()
val base64 = Base64.encodeToString(secretKeySpec.encoded, 0)
val bytes = Base64.decode(base64, 0)
SecretKeySpec(bytes, 0, bytes.size, "AES") == secretKeySpec
在您提到的 Й 是 U+0419 的情况下,大多数西里尔字符以前导 0 开头。这显然意味着在转换之前在奇数字符数组之前添加 0 会有所帮助。
测试javascript似乎这仅对于1个字母长的字符串来说是安全的:Ѓ(U+0403)返回403,Ѕ(U+0405)返回405,但是ЃЅ返回403405而不是04030405或4030405,这更糟糕,因为它是偶数,不会触发异常,并且可以解码为完全不同的东西。
This 处理用前导零填充的问题可能有助于 javascript 部分。
您好,您可以使用 Unicode 编码。在您的情况下,字符
Й
将在客户端转换为 \u0419
。然后在服务器端你可以使用 Java,如下所示:
import org.apache.commons.lang.StringEscapeUtils;
// Russian char = "Й"
String hex = "\u0419";
String unescapeJava = StringEscapeUtils.unescapeJava(hex);
System.out.println("unescapeJava => " + unescapeJava);
问题出在这一行:
number += string.charCodeAt(i).toString(16);
当循环到达字符“Й”时,
string.charCodeAt(i)
返回十进制的 1049,但是当您将其转换为十六进制(基数 16)时,它会变成“419”,您可以直接追加它。将字符代码附加到 0x80 恰好是正确的,但超出此点就不正确。
在这种情况下,您想要附加的是根据 UTF-8 规范的字符的 2 字节编码。维基百科有一个很好的总结和一些关于如何正确编码 UTF-8 文本的示例:https://en.wikipedia.org/wiki/UTF-8
这个链接解释了如何在js中从字符串获取UTF-8字节数组:如何将UTF8字符串转换为字节数组?
而不是
sb.append(new String(bytes,"UTF-8"));
试试这个
sb.append(new String(bytes,"Windows-1251"));