使用场景
我们已经实现了一个Web服务,我们的Web前端开发人员在内部使用了该服务(通过php
API)来显示产品数据。用户在网站上输入内容(即查询字符串)。在内部,网站通过api调用服务。
注意:我们使用restlet,而不是tomcat
原始问题
Firefox 3.0.10似乎尊重浏览器中选择的编码,并根据选择的编码对URL进行编码。这确实会导致ISO-8859-1和UTF-8的查询字符串不同。
我们的网站转发来自用户的输入,但不会进行转换(应该转换),因此它可能会通过api调用使用包含德国变音符号的查询字符串的webservice来调用该服务。
即查询部分看起来像
...v=abcädef
如果选择“ ISO-8859-1”,则发送的查询部分看起来像
...v=abc%E4def
但是如果选择“ UTF-8”,则发送的查询部分看起来像
...v=abc%C3%A4def
所需解决方案
在我们控制服务的过程中(因为我们已经实现了它),我们想在 服务器端 检查调用是否包含非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;
}
题
这会捕获所有无效(非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") );
}
打印:
v=abc?def
v=abcädef
v=abcädef
v=abcädef
并且 不会 抛出IllegalArgumentException 叹气
我问了同样的问题,
在Tomcat上处理URI中的字符编码
我最近找到了一个解决方案,对我来说效果很好。您可能需要尝试一下。这是您需要做的,
例如,要从查询字符串获取参数,
String name = fixEncoding(request.getParameter("name"));
您可以始终这样做。正确编码的字符串不会更改。
该代码已附加。祝好运!
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;
}
编辑:您的方法由于各种原因而行不通。当出现编码错误时,您不能指望从Tomcat获得的内容。有时你会得到``?’‘?有时候,您什么也得不到,getParameter()返回null。假设您可以检查“?”,那么查询字符串包含有效的“?”会发生什么情况??
此外,您不应拒绝任何请求。这不是您用户的错。正如我在原始问题中提到的那样,浏览器可以使用UTF-8或Latin-1编码URL。用户无法控制。您需要接受两者。将您的servlet更改为Latin-1会保留所有字符,即使它们是错误的也是如此,从而使我们有机会对其进行修复或丢弃。
我在这里发布的解决方案并不完美,但这是迄今为止我们发现的最好的解决方案。
问题内容: 我需要一个可以告诉我字符串是否包含非字母数字字符的方法。 例如,如果字符串为“ abcdef?” 或“abcdefà”,该方法必须返回true。 问题答案: 使用Apache Commons Lang: 另一种方法是遍历String的字符并检查: 您还剩下一个问题:示例字符串“abcdefà”是字母数字,因为是字母。但我认为您希望将其视为非字母数字,对吗? 因此,您可能想使用正则表达式
问题内容: 假设您有一个要测试的字符串,以确保在继续其他代码之前,该字符串包含整数。在Java中,您将使用什么来确定它是否为整数? 问题答案: 如果要确保它 只是 一个整数并将其转换为一个整数,则可以在中使用parseInt。但是,如果要检查字符串是否包含数字,则最好将String.matches与正则表达式配合使用:
问题内容: 如何检查字符串是否已经编码? 例如,如果我编码,我得到。如果我再次对最后一个字符串进行编码,我会得到,如果这样做,我必须先知道它是否已经被编码… 我已经保存了编码参数,我需要搜索它们。我不知道输入参数是什么,要编码还是不编码,所以我必须知道在搜索之前是否必须对它们进行编码或解码。 问题答案: 解码,与原始图像进行比较。如果确实不同,则对原稿进行编码。如果没有区别,则原始文件不会被编码。
问题内容: 我想检查我的字符串是否包含+字符。我尝试了以下代码 但是它没有给出预期的结果。 问题答案: 您需要此: 类的方法不使用正则表达式作为参数,而是使用普通文本。 编辑: 输出:
问题内容: 有谁知道PHP的健壮(和防弹)is_JSON函数代码片段?我(显然)遇到一种情况,我需要知道字符串是否为JSON。 嗯,也许通过JSONLint请求/响应来运行它,但这似乎有点过头了。 问题答案: 如果您使用内置的PHP函数,则 返回最后一个错误(例如, 当您的字符串不是JSON时)。 无论如何通常都会返回。
问题内容: 我需要检查字符串是否包含数字。任何数字。字符串是否为数字,而不是数字,但包含一个数字。 例子: ‘test’=没有数字。 ‘test2’=包含数字。 问题答案: 使用正则表达式: 不使用正则表达式: