【问题标题】:Wrong encoding when running from JAR, from Eclipse works perfectly从 JAR 运行时编码错误,从 Eclipse 运行完美
【发布时间】:2012-11-28 06:13:10
【问题描述】:

我面临类似于How to Force a jar to uses(or the jvm runs in) utf-8 instead of the system's default encoding 的问题。有一个服务器和客户端 java 应用程序。如果我从 Eclipse 运行它们,那么一切正常。如果我制作罐子,那么它们之间交换的字符串就会被破坏(错误的编码)。

如果我使用-Dfile.enconding=utf-8 JVM 参数运行这两个图像,那么它可以正常工作。但是由于上面的链接说它不是最好的解决方案(至少需要从 bat 运行 jar),我试图通过为 BufferedReader 指定编码来解决这个问题。但是它失败了,并且使用 jar 很难调试。

此代码用于发送请求并获取 JSON 格式的一行作为回复。证明回复是UTF-8编码的。

public static String sendRequest (String request) {
    if (request == null) return null;

    try {
        URL url = new URL(request);
        HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
        BufferedReader inReader = new BufferedReader(new InputStreamReader(con.getInputStream(), Charset.forName("UTF-8")));
        String line = inReader.readLine();
        inReader.close();
        return line;
    } catch (Exception e) {
        e.printStackTrace(System.err);
    }

    return null;
}

这就是线条的样子

{"response":[{"uid":123456,"first_name":"Имя","last_name":"Фамилия"}]}

然后我准备在 Gson.fromJson() 中使用它

int beginIndex = reply.indexOf('[');
int endIndex = reply.indexOf(']');
reply = reply.substring(beginIndex + 1, endIndex);
SocialPerson vkPerson = new Gson().fromJson(reply, SocialPerson.class);

之后,使用由 ChannelBuffers.wrappedBuffer() 和 NettyUtils.writeStrings() 生成的 Netty 的 ChannelBuffer 将字符串发送到服务器

我尝试在 Eclipse 中调试客户端和从 jar 运行的服务器,然后 Eclipse 显示,直到字符串真正提供给框架以交付它看起来有效。

然后我从 Jar 调试服务器和客户端运行,一旦收到字符串,它看起来已经像垃圾了。

在服务器端

    private final String username;
    private final String password;

    public SimpleCredentials(ChannelBuffer buffer)
    {
        this.username = NettyUtils.readString(buffer);
        this.password = NettyUtils.readString(buffer);
    }

您认为问题可能出在哪里?抱歉,我无法在此处发布所有代码。

更新: 用户名由 firstName 和 lastName 生成

ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(opCode, NettyUtils.writeStrings(userId, userName, refKey));

【问题讨论】:

  • 你能告诉我们调用 NettyUtils.writeStrings() 的代码吗?
  • @Isaac,我已经更新了。

标签: java utf-8 character-encoding gson netty


【解决方案1】:

当您读取网络流时,如果自动方式失败,您需要手动重新编码您的字符串。您正在使用的库可能忽略了内容编码,或者它可能在 HTTP 响应中丢失。

您的代码中的某处将是一个字节数组,您可以在 String 构造函数中对其进行转换:

String xxx = new String(bytes, "utf-8");

如果你得到的字符串编码错误,你可以检查这个代码:

String rightEncoded = new String(wrongEncodedString.getBytes("Cp1252"), "utf-8");

【讨论】:

  • 好吧,我已经从框架中得到它作为字符串。我应该从字符串中获取字节并构造一个具有指定编码的新字符串吗?顺便说一句,否决票不是来自我:)
  • 我可以知道我得到的字符串的编码吗?我不确定它是 cp1252
  • 在忍者谷歌搜索中,我发现这种编码可能是默认编码。如果这不起作用,请尝试其他类似 us-ascii 的方法。
  • Default encoding in Java 这听起来是个值得我研究的问题
  • 以编程方式设置系统属性会影响在同一个 JVM 中运行的所有代码,这是很危险的,尤其是在讨论这种低级系统属性时。
【解决方案2】:

您不应该使用file.encoding 系统属性。

避免此类编码问题的最佳方法是永远不要假设任何关于默认平台编码的内容,并且在构造阅读器或将字节转换为字符串时始终提供编码,反之亦然。

您的 sendRequest 方法在处理编码方面似乎没问题:它从输入中读取字符,明确提到它希望流以 UTF-8 编码。

但是,我们看不到客户端/服务器序列的另一端。引用你的话:

之后,使用 Netty 将字符串发送到服务器 使用 ChannelBuffers.wrappedBuffer() 生成的 ChannelBuffer 和 NettyUtils.writeStrings()

你也提到这里不能附上整个代码,这是可以理解的;因此,我建议您查看发送这些字符串的准确方式,以及在发送时是否明确指定编码。

EDIT 根据 OP 的更新:好吧,很抱歉我不熟悉 Netty,但我还是会在这里试一试。 NettyUtils.writeStrings() 或任何调用它的代码不接受字符编码吗?我在网上找不到任何NettyUtils 的JavaDoc。在这里和我一起工作。 :-)

【讨论】:

  • 我似乎不是 Netty 的东西,而是框架作者的一个类,所以我可能也需要联系他
  • 我同意。我查看了NettyUtils 的代码,它最终调用StringEncoderWrapper 来实际进行序列化。我确信它(或某些最终被 它调用的代码)最终会对默认平台编码做出假设。