V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
springmarker
V2EX  ›  Java

要崩溃了,一个编码问题缠了我 3 小时

  •  
  •   springmarker · 2017-02-18 02:27:26 +08:00 · 6697 次点击
    这是一个创建于 2873 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需要对字符串进行加密,写好了,发现结果跟预期不一样:
    字符串已经硬写到 java 文件中了,在 WEB 服务下自动变成 gbk 编码的,在 Application 下就是 utf-8 编码。
    比如“周杰伦”这个字符串,
    输出 "周杰伦".getBytes();

    WEB 下是 -42 -36 -67 -36 -62 -41
    Application -27 -111 -88 -26 -99 -80 -28 -68 -90

    看 byte 个数基本都能猜出是什么编码了,一转码一看还真是有问题。

    我已经把能调成 utf-8 的全调成 utf-8 了,还是不对,真是要崩溃了,要是数据库, springmvc 啥的乱码还好说,这个完全不知道咋回事。
    编辑器是 IDEA 2016.3 , spring4.3.6 , tomcat8 ,两个模式下环境一模一样。

    java 文件用别的编辑器看也是 utf-8 编码, class 用 IDEA 和 jd-gui 看也是很正常,也没有乱码。

    不知到要把锅甩给谁了, Spring ? IDE ?

    有环境的兄弟帮忙运行看一下有没有问题,看是不是我的锅
    System.out.println(new String(new byte[]{-27, -111, -88, -26, -99, -80, -28, -68, -90}));
    System.out.println(new String(new byte[]{-42,-36,-67,-36,-62,-41}));
    第 1 条附言  ·  2017-02-18 13:21:06 +08:00
    很多人可能没看懂我的意思

    System.out.println(new String(new byte[]{-27, -111, -88, -26, -99, -80, -28, -68, -90}));
    System.out.println(new String(new byte[]{-42,-36,-67,-36,-62,-41}));

    第一个是 utf-8 编码,第二个是 gbk 编码,我运行的环境配置的都是 utf-8 编码,
    我希望在 spring 的 web 环境的正常情况下,第一个是正常,第二个是乱码 ,但是结果却相反,
    反而在 application 下却是正常的。
    输出 Charset.defaultCharset().name();
    web 是 gbk , application 是 utf-8 ,中文字符串在控制台输出都是正常的。

    同一个 ide ,同一个控制台, win10 系统,奇怪的虽然两个环境下编码不一样,但是控制台中文输出字符串都是正常的。

    这也是我希望大家帮忙在 spring 的 web 环境下运行一下,看一看是不是我配置有问题
    第 2 条附言  ·  2017-02-18 15:55:27 +08:00
    好了,问题解决了,也不知道锅是不是该甩给 idea , idea 启动普通的 application 时候,编码默认是 utf-8 ,而启动 tomcat 的时候,也不知道是什么原因,默认编码不是 utf-8 ,而是 gbk ,在 eclipse 中就没这样的问题。

    几位朋友说加-Dfile.encoding=UTF-8 ,一开始我只在 tomcat 的 vm options 加入,发现控制台乱码。
    后来才知道这样只是启动 web 服务指定了编码, ide 还是按照原来的编码在控制台显示中文,所以造成显示乱码,但是计算结果没问题,所以还需要在 idea 的配置文件中指定启动 idea 的配置文件的编码 idea.exe.vmoptions 文件中 添加-Dfile.encoding=UTF-8 ,一开始配置完成发现没用,后来发现我当时设置 idea 启动的是 64 位,竟然还有个 64 位的配置文件,添加完成解决。

    最后感谢各位的帮忙!
    36 条回复    2017-02-18 21:22:46 +08:00
    a87150
        1
    a87150  
       2017-02-18 02:39:48 +08:00
    IDEA utf-8 运行 System.out.println(new String(new byte[]{-27, -111, -88, -26, -99, -80, -28, -68, -90})); 是周杰伦,另外一个乱码。不知道对你有没有帮助
    springmarker
        2
    springmarker  
    OP
       2017-02-18 02:44:03 +08:00 via Android
    @a87150 你是 spring 的 web 环境吗?我的是在这个环境下出现问题的,在 application 中就没问题
    binux
        3
    binux  
       2017-02-18 02:45:05 +08:00   ❤️ 2
    任何不显式要求编码的 bytes 转化都要小心。
    等你长大了就懂了。
    springmarker
        4
    springmarker  
    OP
       2017-02-18 02:51:09 +08:00 via Android
    @binux 我的需求并不是转化,我的情况是在两个环境中发现同一个字符串 getByte()的结果不一样
    binux
        5
    binux  
       2017-02-18 02:53:12 +08:00
    @springmarker #4 你 getByes() 就是将 unicode 转 二进制编码啊!
    thekll
        6
    thekll  
       2017-02-18 03:27:52 +08:00
    检查 web 容器的编码设置。
    EthanZ
        7
    EthanZ  
       2017-02-18 04:19:43 +08:00
    try add @RequestMapping(*********,produces = "application/json; charset=utf-8")
    tt7
        8
    tt7  
       2017-02-18 05:00:51 +08:00
    Java 的 getBytes() 不加参数是用当前 platform 默认 charset 编码, 应该不是你 IDE 设置的文件编码; new String() 同理。 Hakurei 同学已经告诉了你答案…
    ynyounuo
        9
    ynyounuo  
       2017-02-18 05:58:35 +08:00
    这是一个「锟斤拷」的问题
    zhilincom
        10
    zhilincom  
       2017-02-18 08:06:50 +08:00 via Android
    Java 内部默认编码不是 UTF-16 吗?还有.java 文件的存储编码和编译运行时的内部编码是不相关的。
    szq8014
        11
    szq8014  
       2017-02-18 08:36:51 +08:00   ❤️ 2
    vm 参数加上 -Dfile.encoding=UTF-8 试试呢?
    YzSama
        12
    YzSama  
       2017-02-18 08:45:29 +08:00 via iPhone
    试试 jvm 加编码参数。
    luguanyu1234
        13
    luguanyu1234  
       2017-02-18 08:46:14 +08:00
    请用这个重载 String::getBytes(String charsetName)
    直接写明需要的编码类型

    如果用没有参数的那个 getBytes ,这个 charsetName 是系统默认编码类型,
    你可以调用 Charset.defaultCharset().name()看下 两种情况下是不是不一样的
    mgcnrx11
        14
    mgcnrx11  
       2017-02-18 09:11:42 +08:00 via iPhone
    tomcat 在 IDEA 下跑会用系统默认编码,是不是控制台输出都已经乱码了?加 VM 参数-Dfile.encoding=UTF-8 可破
    angelface
        15
    angelface  
       2017-02-18 09:34:09 +08:00
    我猜, 你用的是 Tomcat?
    guoxu1231
        16
    guoxu1231  
       2017-02-18 11:59:46 +08:00 via iPhone
    三小时就奔溃了?看来楼主不太适合程序员这个职业啊~
    fantastM
        17
    fantastM  
       2017-02-18 12:05:34 +08:00
    vim /usr/local/tomcat7/conf/server.xml

    <Connector port="8080" protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443" URIEncoding="UTF-8"/>
    vh2h
        18
    vh2h  
       2017-02-18 12:08:13 +08:00
    这不是你的锅

    这应该是周杰伦的锅
    springmarker
        19
    springmarker  
    OP
       2017-02-18 12:43:29 +08:00
    @EthanZ
    并不是 url 参数乱码问题,要是这种问题就好解决了

    @szq8014 @YzSama
    加参数运行结果倒是对了,但是控制台输出中文的全是乱码

    @luguanyu1234
    在 web 下是 GBK , application 下是 UTF-8 ,这跟之前猜的一样,问题是,怎么让 web 下默认是 utf-8

    @mgcnrx11
    加参数运行结果是对的,但是控制台中文变成了乱码,不加参数的时候,虽然 web 下默认编码变成了 gbk ,但控制台输出的依然是正常的,反而在 web 下,输出 utf-8 编码的 byte 是乱码,这也是我想让你们帮忙测试一下我最后写的,看是不是个例

    @angelface
    没错,但是不用猜,内容里写了

    @fantastM
    URIEncoding ,应该是解决 url 参数乱码的问题,况且就算加了,也没什么用

    @guoxu1231
    发帖时大晚上的,想睡觉,但是不解决心里不舒服,于是开始暴躁了

    @vh2h
    发现用包子的名字也不好使,锅要不要甩给他
    rogerchen
        20
    rogerchen  
       2017-02-18 12:54:23 +08:00 via Android
    @springermaker
    1.String 的内部表示
    2.getBytes 的参数
    3.网页模板的 charset

    把我觉得锅在 3 上
    szq8014
        21
    szq8014  
       2017-02-18 12:57:48 +08:00
    @springmarker 控制台输出乱码就不是应用程序的事儿了吧,可以再开一个帖子问终端乱码怎么解决?(手动滑稽)

    如果是 IDE 集成的那种控制台,可以看看 IDE 相关字符集的设置,也可以直接给 IDE 来个 file.encoding=UTF-8 毕竟都是 java 。
    如果是 *nix 的,我也不太了解,确定安装了中文字体?
    fantastM
        22
    fantastM  
       2017-02-18 13:26:26 +08:00
    @springmarker 是不是 IDEA 的 Setting->Build,Execution,Deployment->Compiler->Java Compiler 的配置不正常了
    springmarker
        23
    springmarker  
    OP
       2017-02-18 13:27:18 +08:00
    @rogerchen
    不是传值的问题,字符串已经硬写在 java 中了。

    @szq8014
    ide 集成的控制台,设置的都是 utf-8 ,但是在同一环境下,同一个控制台,中文字符串输出都是正常的,但是在 spring 的 web 环境下运行字符串 getByte()却是 gbk 编码,在 test 下直接运行就是 utf-8 编码,很奇怪的问题
    springmarker
        24
    springmarker  
    OP
       2017-02-18 13:40:51 +08:00
    @fantastM
    看着并没有不正常,编译器用 javac 和 eclipse 都不行,要是有问题的话,按理说 application 输出也该是错误的
    mgcnrx11
        25
    mgcnrx11  
       2017-02-18 13:41:56 +08:00 via iPhone
    @springmarker 你确定 ide 设置的 console 是 utf-8 ?我从来没有找到哪里能设置 IDEA 的 console 编码。

    控制台编码和不同终端的设置相关,默认跟操作系统的一致
    wohenyingyu02
        26
    wohenyingyu02  
       2017-02-18 13:45:28 +08:00
    不可以加 bom 头么
    springmarker
        27
    springmarker  
    OP
       2017-02-18 13:49:59 +08:00
    @mgcnrx11
    这个确实没有设置的地方,网上看到的都是加上-Dfile.encoding=UTF-8 这一句,但是加上之后, application 还是正常的,跟之前结果一样。但是 web 下中文都是乱码的,输出的结果却是正常的。
    其实我更想知道怎么解决。
    springmarker
        28
    springmarker  
    OP
       2017-02-18 13:52:46 +08:00
    @wohenyingyu02
    跟 bom 没关系吧,况且加了 bom 的话,容易出问题吧,之前有 bom 的 java 文件怎么编译都编译不过
    SoloCompany
        29
    SoloCompany  
       2017-02-18 18:28:35 +08:00 via iPhone
    https://youtrack.jetbrains.com/issueMobile/WI-21388

    不知道对你有没有帮助,建议你还是先看一下 idea 各个 encodings 设置是怎么生效的吧
    raptor
        30
    raptor  
       2017-02-18 18:59:28 +08:00   ❤️ 3
    第一,这是 windows 的锅, IDEA 启动 tomcat 的时候用的系统编码,所以是 GBK
    第二,其实这也不怪 windows ,因为早年工信部要求计算机系统都必须用 GBK ,现在的 windows 为了保持兼容,所以还是 GBK ,英文版 windows 是 unicode 的
    第三,现在除了中文 windows 以外,其它系统基本都是 unicode ,所以珍爱生命,远离中文 windows
    binux
        31
    binux  
       2017-02-18 19:28:29 +08:00
    我一开始就说了「任何不显式要求编码的 bytes 转化都要小心」

    你显式指定编码不就完了,你管它环境是什么啊!
    就算你要依据环境自动配置,你不会自己读取环境变量,然后手动指定吗?
    binbinyouliiii
        32
    binbinyouliiii  
       2017-02-18 19:59:50 +08:00
    @binux 一开始我以为你说的意思是 getByte("utf-8")
    binux
        33
    binux  
       2017-02-18 20:03:38 +08:00
    @binbinyouliiii #32 我说的就是 getByte("utf-8") 啊。。
    springmarker
        34
    springmarker  
    OP
       2017-02-18 20:25:08 +08:00
    @binux 我当时试了一下,结果输出还是乱码,你这么一说好像我当时输出的姿势不太对,刚才试了一下的确可以,谢谢
    binux
        35
    binux  
       2017-02-18 20:50:41 +08:00
    @springmarker #34 你的输出编码,要和展示编码一致啊
    billlee
        36
    billlee  
       2017-02-18 21:22:46 +08:00
    不要用 new String(byte[]) 接口,以及任何不指定编码就把字节流转换成字符串的接口,不指定编码就对字节流进行解码就是耍流氓
    显式地用 new String(byte[], Charset)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1116 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 18:48 · PVG 02:48 · LAX 10:48 · JFK 13:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.