如果只存在一个非法字符,使用 utf-8 的字符编码会破坏所有数据

Character encoding with utf-8 breaks all data if just one illegal character is present

在我的应用程序中通过 REST 服务读取数据时,我有一个奇怪的行为。

我总是用 utf-8 编码我的 REST 服务。这已被证明是一个 安全的选择 - 直到现在。我来自丹麦,我们有一些特殊字符,例如:æøå。

所以对于这组特定的数据,用户在应用程序中输入了一个笑脸 - 并且数据已同步到服务器。当数据随后被发送回phone ALL时,请求中的数据得到"scrambled"。如果我在任何其他工具(如各种浏览器,例如 PostMan)中尝试相同的请求,那么一切看起来都正常(字符集是 utf-8,只有笑脸无法显示)。但是,在我的应用程序中,所有非英语字符都被打乱了。

单击 here to see the url with the smiley - and here 以查看没有笑脸的 url(只是不同的截止时间)。 编辑:链接不再有效....

我创建了一个小的测试应用程序来从 Appcelerator 内部显示问题:

查看:

<Alloy>
    <Window class="container">
        <View>
            <Button id="label1" class="heading" onClick="reload1">Load with smiley</Button>
            <Button id="label2" class="heading" onClick="reload2">Load without smiley</Button>
            <ListView id="nameList" defaultItemTemplate="templateName">
                <Templates>
                    <ItemTemplate name="templateName">
                        <Label bindId="name"/>
                    </ItemTemplate>
                </Templates>
                <ListSection>
                    <ListItem/>
                </ListSection>
            </ListView>
        </View>
    </Window>
</Alloy>

风格:

".container": {
    top: 20,
    backgroundColor:"white",
    orientationModes: [Ti.UI.PORTRAIT]
}
"Label": {
    width: Ti.UI.SIZE,
    height: Ti.UI.SIZE,
    backgroundColor: 'transparent',
    left:10, 
    color: "#000"
}

".heading": { top:15, 
    font: {
        fontSize: '18dp',
        fontStyle: 'bold'
    }
}

"#label1":{left: 10}
"#label2":{right: 10}
"#nameList":{
    top:'50dp'
}

控制器:

function reload1(){
    reload('http://url1');
}
function reload2(){
    reload('http://url2');
}

function reload(url){
    var list = [];
    $.nameList.sections[0].items = [];

    var xhr = Ti.Network.createHTTPClient({
                timeout : 20000 
              });

    var name = 'speciesName';
    xhr.open('GET', url);
    xhr.onload = function(e) {
        var responseJSON = {};
        Ti.API.info("Response headers: " + this.getAllResponseHeaders());
        try {
            responseJSON = JSON.parse(this.responseText);
            if(responseJSON.data){
                _.each(responseJSON.data,function(rec){
                    if(rec[name] && rec[name] != ''){
                        var item = {template: "templateName",name : { text: rec[name] }};
                        list.push(item);
                    }
            });
            $.nameList.sections[0].items = list;
            }
        } catch (e) {
            Ti.API.error('[REST API] apiCall PARSE ERROR: ' + e.message);
            Ti.API.error('[REST API] apiCall PARSE ERROR: ' + this.responseText);
            status = false;
            error = e.message;
        }
    };
     // function called when an error occurs, including a timeout
    xhr.onerror = function(e) {
         Ti.API.debug(e.error);
         alert('error');
    };
    xhr.send();
}

$.index.open();
reload1();

当您启动应用程序时,它会显示 "scrambled" 个字符的数据。然后,您可以使用顶部的按钮在数据集 with/without 和笑脸之间切换。

问题在 iOS 和 Android 上是一致的。我是 运行 Ti SDK 5.1.2 - 在提交 "real" 应用程序更新之前我不敢升级 :-)

理想情况下,我还希望能够在移动设备上显示笑脸。但是,我可以忍受它没有正确显示 - 只要它不会破坏整个数据集。

非常感谢 thoughts/ideas/insight:-)

/约翰

所以字符串从服务器返回为:

"comments":"Huggede under træet og gav en helt fantastisk fight.\nMin stang knækkede og jeg dumpede i åen??????"

笑脸表情符号已作为 UTF-8 代码单元发送:ed a0 bd ed b8 80

它们应该 JSON/JS 转义为 \uD83D\uDE00 =

这是查看编码问题的好资源https://r12a.github.io/apps/conversion/

好的。结果证明这是一个与 Titanium/Appcelerator 无关的问题 - 除了如果只有一个字符不适合字符集,整个请求就会被破坏。

后端服务器是 IBM XWork 服务器,结果发现 REST 服务使用了发送字符的 ResponseWriter (Java)。在发送字节流的 DataOutputStream (Java) 将其更改为 return 解决了问题。

如果其他人 运行 遇到类似的问题,那么我已经写了一篇 blog article about this,您可以在其中了解更多信息。该解决方案并非特定于 IBM XWork - 但适用于使用 Java :-)

的任何后端

/约翰