当前位置: 首页 > 面试题库 >

如何确定字符串是否包含无效的编码字符

单于奇略
2023-03-14
问题内容

使用场景

我们已经实现了一个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))

  1. 如果character.getBytes()[0]等于“?”的63
  2. 如果Character.getType(character.charAt(0))返回OTHER_SYMBOL

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中的字符编码

我最近找到了一个解决方案,对我来说效果很好。您可能需要尝试一下。这是您需要做的,

  1. 将您的URI编码保留为Latin-1。在Tomcat上,将URIEncoding =“ ISO-8859-1”添加到server.xml中的连接器。
  2. 如果必须手动进行URL解码,也可以将Latin1用作字符集。
  3. 使用fixEncoding()函数修正编码。

例如,要从查询字符串获取参数,

  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’=包含数字。 问题答案: 使用正则表达式: 不使用正则表达式: