Character encoding 如果仅存在一个非法字符,则使用utf-8进行字符编码会中断所有数据

Character encoding 如果仅存在一个非法字符,则使用utf-8进行字符编码会中断所有数据,character-encoding,appcelerator,appcelerator-titanium,Character Encoding,Appcelerator,Appcelerator Titanium,通过REST服务从我的应用程序中读取数据时,我有一种奇怪的行为 我总是用utf-8对我的REST服务进行编码。到目前为止,这已被证明是一种安全的选择。我来自丹麦,我们有很多特别的角色,比如:æå 因此,对于这组特定的数据,用户在应用程序中输入了一个笑脸,并且数据已同步到服务器。当数据随后被发送回手机时,请求中的所有数据都被“加扰”。如果我在任何其他工具(如各种浏览器等)中尝试相同的请求,那么一切看起来都正常(字符集为utf-8,只有笑脸无法显示)。然而,在我的应用程序中,所有非英语字符都会被置乱

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

我总是用
utf-8
对我的REST服务进行编码。到目前为止,这已被证明是一种安全的选择。我来自丹麦,我们有很多特别的角色,比如:æå

因此,对于这组特定的数据,用户在应用程序中输入了一个笑脸,并且数据已同步到服务器。当数据随后被发送回手机时,请求中的所有数据都被“加扰”。如果我在任何其他工具(如各种浏览器等)中尝试相同的请求,那么一切看起来都正常(字符集为
utf-8
,只有笑脸无法显示)。然而,在我的应用程序中,所有非英语字符都会被置乱

单击此处可查看带笑脸的url,也可查看不带笑脸的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();
控制器:

<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();
当你启动应用程序时,它会显示带有“加扰”字符的数据。然后,您可以使用顶部的按钮在有/没有笑脸的数据集之间切换

这个问题在iOS和Android上是一致的。我正在运行
Ti SDK 5.1.2
-我不敢升级,除非我很快向我的“real”应用程序提交了更新:-)

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

非常感谢您的任何想法/想法/见解:-)


/John

因此字符串从服务器返回为:

“评论”:“哈格德在幻想曲的战斗中被击倒了。”

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


它们应该是JSON/JS,转义为
\uD83D\uDE00
=Ok。事实证明,这是一个与Tianium/Appcelerator无关的问题——除了如果只有一个字符不适合角色集,整个请求就会被破坏

后端服务器是一个IBMXWork服务器,结果证明REST服务使用了一个发送字符的ResponseWriter(Java)。将此更改为在DataOutputStream(Java)处返回,它发送一个字节流,从而解决了这个问题

如果其他人遇到类似的问题,那么我写了一篇文章,你可以从中了解更多。该解决方案并不特定于IBM XWork,但适用于使用Java的任何后端:-)


/约翰

感谢您对TiSlack的评论和讨论。事实证明,这是一个漫长得多的解决之旅——正如我作为答案所写的:——)