要崩溃了,一个编码问题缠了我 3 小时 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
springmarker
V2EX    Java

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

  •  
  •   springmarker 2017-02-18 02:27:26 +08:00 7228 次点击
    这是一个创建于 3165 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需要对字符串进行加密,写好了,发现结果跟预期不一样:
    字符串已经硬写到 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=")
    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") 啊。。
        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     Solana     2671 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 14:37 PVG 22:37 LAX 07:37 JFK 10:37
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86