Dan*_*ler 32 java string unicode encoding
使用场景
我们已经实现了一个Web服务,我们的Web前端开发人员在内部使用(通过php api)来显示产品数据.在网站上,用户输入内容(即查询字符串).在内部,网站通过api调用服务.
注意:我们使用restlet,而不是tomcat
原始问题
Firefox 3.0.10似乎尊重浏览器中选定的编码,并根据所选编码对URL进行编码.这确实导致ISO-8859-1和UTF-8的不同查询字符串.
我们的网站转发来自用户的输入并且不转换它(它应该),因此它可以通过使用包含德语变音符号的查询字符串调用web服务的api来调用服务.
即查询部分看起来像
...v=abcädef
Run Code Online (Sandbox Code Playgroud)
如果选择"ISO-8859-1",则发送的查询部分看起来像
...v=abc%E4def
Run Code Online (Sandbox Code Playgroud)
但是如果选择"UTF-8",则发送的查询部分看起来像
...v=abc%C3%A4def
Run Code Online (Sandbox Code Playgroud)
期望的解决方案
当我们控制服务时,因为我们已经实现了它,我们想在服务器端检查调用是否包含非utf-8字符,如果是,则以4xx http状态响应
当前的解决方案
检查每个字符(== string.substring(i,i + 1))
码
protected List< String > getNonUnicodeCharacters( String s ) {
final List< String > result = new ArrayList< String >();
for ( int i = 0 , n = s.length() ; i < n ; i++ ) {
final String character = s.substring( i , i + 1 );
final boolean isOtherSymbol =
( int ) Character.OTHER_SYMBOL
== Character.getType( character.charAt( 0 ) );
final boolean isNonUnicode = isOtherSymbol
&& character.getBytes()[ 0 ] == ( byte ) 63;
if ( isNonUnicode )
result.add( character );
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
题
这会捕获所有无效(非utf编码)字符吗?你们中有谁有更好(更容易)的解决方案吗?
注意:我使用以下代码检查了URLDecoder
final String[] test = new String[]{
"v=abc%E4def",
"v=abc%C3%A4def"
};
for ( int i = 0 , n = test.length ; i < n ; i++ ) {
System.out.println( java.net.URLDecoder.decode(test[i],"UTF-8") );
System.out.println( java.net.URLDecoder.decode(test[i],"ISO-8859-1") );
}
Run Code Online (Sandbox Code Playgroud)
这打印:
v=abc?def
v=abcädef
v=abcädef
v=abcädef
Run Code Online (Sandbox Code Playgroud)
它并没有抛出IllegalArgumentException 叹息
ZZ *_*der 32
我问了同样的问题,
我最近找到了一个解决方案,它对我来说效果很好.你可能想尝试一下.这是你需要做的,
例如,要从查询字符串中获取参数,
String name = fixEncoding(request.getParameter("name"));
Run Code Online (Sandbox Code Playgroud)
你总能做到这一点.具有正确编码的字符串不会更改.
代码附后.祝好运!
public static String fixEncoding(String latin1) {
try {
byte[] bytes = latin1.getBytes("ISO-8859-1");
if (!validUTF8(bytes))
return latin1;
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
// Impossible, throw unchecked
throw new IllegalStateException("No Latin1 or UTF-8: " + e.getMessage());
}
}
public static boolean validUTF8(byte[] input) {
int i = 0;
// Check for BOM
if (input.length >= 3 && (input[0] & 0xFF) == 0xEF
&& (input[1] & 0xFF) == 0xBB & (input[2] & 0xFF) == 0xBF) {
i = 3;
}
int end;
for (int j = input.length; i < j; ++i) {
int octet = input[i];
if ((octet & 0x80) == 0) {
continue; // ASCII
}
// Check for UTF-8 leading byte
if ((octet & 0xE0) == 0xC0) {
end = i + 1;
} else if ((octet & 0xF0) == 0xE0) {
end = i + 2;
} else if ((octet & 0xF8) == 0xF0) {
end = i + 3;
} else {
// Java only supports BMP so 3 is max
return false;
}
while (i < end) {
i++;
octet = input[i];
if ((octet & 0xC0) != 0x80) {
// Not a valid trailing byte
return false;
}
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
编辑:您的方法由于各种原因不起作用.当存在编码错误时,您无法依靠从Tomcat获得的内容.有时你得到 或?其他时候,你不会得到任何东西,getParameter()返回null.假设您可以检查"?",您的查询字符串包含有效"?"的情况会怎样??
此外,你不应该拒绝任何要求.这不是您的用户的错.正如我在原始问题中提到的,浏览器可能以UTF-8或Latin-1编码URL.用户无法控制.你需要接受两者.将servlet更改为Latin-1将保留所有字符,即使它们是错误的,也可以让我们有机会修复它或将它丢弃.
我在这里发布的解决方案并不完美,但它是迄今为止我们发现的最好的解决方案.
ant*_*nte 14
您可以使用CharsetDecoder配置为在找到无效字符时抛出异常:
CharsetDecoder UTF8Decoder =
Charset.forName("UTF8").newDecoder().onMalformedInput(CodingErrorAction.REPORT);
Run Code Online (Sandbox Code Playgroud)
这是我用来检查编码的内容:
CharsetDecoder ebcdicDecoder = Charset.forName("IBM1047").newDecoder();
ebcdicDecoder.onMalformedInput(CodingErrorAction.REPORT);
ebcdicDecoder.onUnmappableCharacter(CodingErrorAction.REPORT);
CharBuffer out = CharBuffer.wrap(new char[3200]);
CoderResult result = ebcdicDecoder.decode(ByteBuffer.wrap(bytes), out, true);
if (result.isError() || result.isOverflow() ||
result.isUnderflow() || result.isMalformed() ||
result.isUnmappable())
{
System.out.println("Cannot decode EBCDIC");
}
else
{
CoderResult result = ebcdicDecoder.flush(out);
if (result.isOverflow())
System.out.println("Cannot decode EBCDIC");
if (result.isUnderflow())
System.out.println("Ebcdic decoded succefully ");
}
Run Code Online (Sandbox Code Playgroud)
编辑:更新了Vouze建议
归档时间: |
|
查看次数: |
90761 次 |
最近记录: |