【问题标题】:Java servlet doesn't handle special characters correctly (like ć)Java servlet 不能正确处理特殊字符(如 ć)
【发布时间】:2021-05-31 17:10:23
【问题描述】:

我有一个 java servlet,它读取 javascript 前端发送的参数。 javascript前端使用:

escape("{€ć") which becomes "%7B%u20AC%u0107"

Java servlet 就是这样做的:

private static final Pattern JAVASCRIPT_ESCAPE_SEQUENCE= Pattern.compile("%(u[0-9a-fA-F]{4}|[0-9a-fA-F]{2})");




    static String unescape(String input) {
    Matcher matcher = JAVASCRIPT_ESCAPE_SEQUENCE.matcher(input);
    StringBuffer sb = new StringBuffer(input.length());
    while(matcher.find()) {
        String escapeSequence = matcher.group(1);
        if (escapeSequence.startsWith("u")) {
            escapeSequence = escapeSequence.substring(1);
        }
        char c = (char) Integer.parseInt(escapeSequence, 16);
        //System.out.println(" converted  " + Integer.parseInt("0107", 16));
        matcher.appendReplacement(sb, Character.toString(c));
    }
    matcher.appendTail(sb);
    return sb.toString();
}

String sDecodedContent = this.unescape(requestContent);

在 Java 中,变量 sDecodedContent 不是“{€ć”而是“{€?”并将它的字符串发送到后端,后端将不正确的字符串存储到数据库中。 为什么 ć 没有被正确解码? 问候

【问题讨论】:

  • 尝试使用调试器并找出或检查 Character.toString(c); 实际为您提供的值是您从注释行中获得的值。

标签: java utf-8 decode


【解决方案1】:

在 Java 中,变量 sDecodedContent 不是“{€ć”而是“{€?”

这是不正确的。

您未能在粘贴中包含 JAVASCRIPT_ESCAPE_SEQUENCE,但假设它不是完全损坏的,c 最终将具有 0x0107 的值。

那么让我们开始吧:

char c = 0x0107;
System.out.println(Character.toString(c));

这会按预期打印ć,并且对该字符串的一些额外检查表明,代码点为 0x0107 的字符确实在您的字符串中,这并不奇怪。 Java 不是随意破坏或设计愚蠢的,所以这是有道理的。

那么你为什么要观察别的东西呢?

因为无论System.out 将其输出发送到什么,它都只是一个流——一袋字节。字符集转换无处不在。 Java 认为它需要解码该字符以使其进入 sysout 所需的字符集编码是 A,然后将这些字节呈现回字符串并显示给你的眼球,无论是什么过程,都认为它是 B,与 A/B 不兼容。或者,它们,但用于呈现它的字体无法处理 0x0107,并且用于指示“我没有此字形”的字形是 ?。如果它不是黑色菱形中的问号,则可能是您设置了极其简单的字体,,更有可能是编码问题。

那么,您是在终端中运行它吗?你配置错了。检查 bash 或 iterm 或您正在使用的任何文档,并检查如何正确配置编码。 Java 正在发送正确的东西;这是错误之后发生的事情。

并将它的字符串发送到后端,后端将错误的字符串存储到数据库中。

同样,java 没有问题,这意味着您的数据库有问题,或者可能是 JDBC 驱动程序。例如,在 mysql 上,您可能使用了 UTF8 数据类型。哪个不是 UTF8(Mysql 相当是一个糟糕的数据库,有很多奇怪的警告,你需要知道才能正确使用它,这毫无意义。我强烈建议你使用远距离的数据库像这样的疣更少),或者您只是将其保留在默认值中,通常是一些北欧 ISO 而不是 UTF8MB4(实际 UTF8 是 mysqlese)。这通常称为“整理”,如果这有助于您阅读您使用的数据库的文档。

测试所有这些东西的简单方法是直接访问源代码:

String test = "\u0107";
System.out.println(test);
sendToDb(test);

如果ć 没有被打印或其他东西到达数据库,你知道它不是java,因为"\u0107" 是代表ć 的文字,不可能被误解和不依赖于任何东西的字符集配置。这就是java源文件中\u转义的用途:确保向例如提供错误的字符集。通过-charsetjavac 命令根本不会影响结果。

您会发现它正在打印?,而数据库也在同样地处理这些字符串。弄乱你的终端和/或数据库的配置,直到它工作为止。

【讨论】:

    猜你喜欢
    • 2016-09-05
    • 1970-01-01
    • 1970-01-01
    • 2016-12-27
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多