Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的解析接受语言头_Java_Servlets_Http Accept Language - Fatal编程技术网

Java中的解析接受语言头

Java中的解析接受语言头,java,servlets,http-accept-language,Java,Servlets,Http Accept Language,请求中的accept language标头通常是一个长而复杂的字符串- 例如 有没有一种简单的方法可以用java解析它?或者一个API来帮助我做到这一点?我建议使用来让容器解析Accept语言,而不是自己尝试管理复杂性。这里有一种解析Accept语言头的替代方法,它不需要servlet容器: String header = "en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2"; for (String str : header.split(","))

请求中的accept language标头通常是一个长而复杂的字符串-

例如


有没有一种简单的方法可以用java解析它?或者一个API来帮助我做到这一点?

我建议使用来让容器解析Accept语言,而不是自己尝试管理复杂性。

这里有一种解析Accept语言头的替代方法,它不需要servlet容器:

String header = "en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2";
for (String str : header.split(",")){
    String[] arr = str.trim().replace("-", "_").split(";");

  //Parse the locale
    Locale locale = null;
    String[] l = arr[0].split("_");
    switch(l.length){
        case 2: locale = new Locale(l[0], l[1]); break;
        case 3: locale = new Locale(l[0], l[1], l[2]); break;
        default: locale = new Locale(l[0]); break;
    }

  //Parse the q-value
    Double q = 1.0D;
    for (String s : arr){
        s = s.trim();
        if (s.startsWith("q=")){
            q = Double.parseDouble(s.substring(2).trim());
            break;
        }
    }

  //Print the Locale and associated q-value
    System.out.println(q + " - " + arr[0] + "\t " + locale.getDisplayLanguage());
}
您可以在此处找到Accept Language标头和相关q值的说明:


非常感谢卡尔·克内赫特尔和迈克·塞缪尔。他们对原始问题的评论为我指明了正确的方向。

记录在案,现在有可能:


ServletRequest.getLocale()
如果可用并且不像某些框架那样被覆盖,那么它肯定是最好的选择

对于所有其他情况,Java8都提供了
Locale.LanguageRange.parse()
,正如Quiang Li前面提到的那样。但是,这只返回一个语言字符串,而不是区域设置。要分析语言字符串,可以使用
Locale.forLanguageTag()
(自Java 7起提供):

final List acceptedLocales=new ArrayList();
最终字符串userLocale=request.getHeader(“接受语言”);
if(userLocale!=null){
最终列表范围=Locale.LanguageRange.parse(userLocale);
如果(范围!=null){
ranges.forEach(languageRange->{
最后一个字符串localeString=languageRange.getRange();
最终语言环境=Locale.forLanguageTag(localeString);
acceptedLocales.add(locale);
});
}
}
返回acceptedLocales;

我们正在使用Spring boot和Java 8。这很有效

在ApplicationConfig.java中编写

@Bean

public LocaleResolver localeResolver() {
    return new SmartLocaleResolver();
}
在我的constants类中有一个列表,它有我们支持的语言

List<Locale> locales = Arrays.asList(new Locale("en"),
                                         new Locale("es"),
                                         new Locale("fr"),
                                         new Locale("es", "MX"),
                                         new Locale("zh"),
                                         new Locale("ja"));
List locales=Arrays.asList(新语言环境(“en”),
新区域设置(“es”),
新区域设置(“fr”),
新区域设置(“es”、“MX”),
新语言环境(“zh”),
新地区("ja);;
并在下面的课堂上写出逻辑

public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
          @Override
         public Locale resolveLocale(HttpServletRequest request) {
            if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
            return Locale.getDefault();
            }
            List<Locale.LanguageRange> ranges = Locale.LanguageRange.parse("da,es-MX;q=0.8");
            Locale locale = Locale.lookup(ranges, locales);
            return locale ;
        }
}
公共类SmartLocaleResolver扩展了AcceptHeaderLocaleResolver{
@凌驾
公共区域设置resolveLocale(HttpServletRequest请求){
if(StringUtils.isBlank(request.getHeader(“接受语言”)){
返回Locale.getDefault();
}
List ranges=Locale.LanguageRange.parse(“da,es-MX;q=0.8”);
Locale=Locale.lookup(范围、区域设置);
返回区域设置;
}
}

上述解决方案缺乏某种验证。如果用户未提供有效的服务器区域设置,则使用
ServletRequest.getLocale()
返回服务器区域设置

我们的网站最近收到各种
接受语言的垃圾邮件请求,如:

  • secret.google.com
  • o-o-8-o-o.com搜索shell比谷歌好得多
  • Google正式推荐o-o-8-o-o.com搜索shell
  • Vitaly统治谷歌☆*:。゜゚・*ヽ(^ᴗ^)ノ*・゜゚。:*☆ ¯\_(ツ)_/¯(ಠ益ಠ)(ಥ‿ಥ)(ʘ‿ʘ)ლ(ಠ_ಠლ)( ͡° ͜ʖ ͡°)ヽ(゚Д゚)ノʕ•̫͡•ʔᶘ ᵒᴥᵒᶅ(=^^=)oO
  • 此实现可以根据支持的有效
    区域设置列表进行可选检查
    。如果不进行此检查,使用
    “test”
    或(2、3、4)的简单请求仍然会绕过
    LanguageRange.parse(String)
    的语法验证

    它允许空值和空值以允许搜索引擎爬虫

    Servlet过滤器

    final String headerAcceptLanguage = request.getHeader("Accept-Language");
    
    // check valid
    if (!HttpHeaderUtils.isHeaderAcceptLanguageValid(headerAcceptLanguage, true, Locale.getAvailableLocales()))
        return;
    
    实用程序

    /**
     * Checks if the given accept-language request header can be parsed.<br>
     * <br>
     * Optional the parsed LanguageRange's can be checked against the provided
     * <code>locales</code> so that at least one locale must match.
     *
     * @see LanguageRange#parse(String)
     *
     * @param acceptLanguage
     * @param isBlankValid Set to <code>true</code> if blank values are also
     *            valid
     * @param locales Optional collection of valid Locale to validate any
     *            against.
     *
     * @return <code>true</code> if it can be parsed
     */
    public static boolean isHeaderAcceptLanguageValid(final String acceptLanguage, final boolean isBlankValid,
        final Locale[] locales)
    {
        // allow null or empty
        if (StringUtils.isBlank(acceptLanguage))
            return isBlankValid;
    
        try
        {
            // check syntax
            final List<LanguageRange> languageRanges = Locale.LanguageRange.parse(acceptLanguage);
    
            // wrong syntax
            if (languageRanges.isEmpty())
                return false;
    
            // no valid locale's to check against
            if (ArrayUtils.isEmpty(locales))
                return true;
    
            // check if any valid locale exists
            for (final LanguageRange languageRange : languageRanges)
            {
                final Locale locale = Locale.forLanguageTag(languageRange.getRange());
    
                // validate available locale
                if (ArrayUtils.contains(locales, locale))
                    return true;
            }
    
            return false;
        }
        catch (final Exception e)
        {
            return false;
        }
    }
    

    其实并没有那么复杂:用逗号将冒号后面的部分分开,然后在每组中查找分号,然后解析语言代码和q因子。在将
    '-'
    s替换为
    '
    s之后,语言代码往往对应于
    java.util.Locale
    s。您真的需要自己解析它吗能否使用[Http]ServletRequest.getLocale[s]让容器来处理复杂性?@bkail:请把你的评论放在一个答案中,因为它是“正确的”肯定的。这是否是一个servlet问题并不明显,尽管我猜java ee标记的存在表明OP使用servlet API可能会感到满意。除非你计划直接支持每一个可能的区域设置,否则请提供服务rRequest.getLocales可能是一个更好的选择。问题是
    ServletRequest。如果用户没有提供有效的服务器区域设置,getLocales
    将返回服务器区域设置。要防止语言垃圾请求,您必须自己在
    LanguageRange.parse(字符串)中解析它
    很方便。@djmj只要检查相关的
    Accept Language
    头是否存在就足够简单了。不过,您是对的,较新的JDK添加了其他可能有用的API(这个答案是从2011年开始的!)。如果机器人程序滥用
    Accept Language
    向您的网站发送垃圾邮件,则该网站存在,但没有有效的元素。如果某些google机器人对您的页面进行爬网,则“缺席”仍然有效。请参阅,如果您需要区域设置列表,可以使用
    Locale.LanguageRange.parse(requestedLangs).stream().sorted(Comparator.comparing(Locale.LanguageRange::getWeight).reversed()).map(range->new Locale(range.getRange()).collect(Collectors.toList());
    @Alex:根据javadoc,您不需要对返回的
    列表进行排序:“与加权列表不同,按优先级排序的列表中的语言范围根据其优先级按降序排序。第一语言范围具有最高优先级,并且最符合用户的偏好。”。因此,您的代码可以是:
    Locale.LanguageRange.parse(requestedLangs).stream().map(range->new L
    
    List<Locale> locales = Arrays.asList(new Locale("en"),
                                             new Locale("es"),
                                             new Locale("fr"),
                                             new Locale("es", "MX"),
                                             new Locale("zh"),
                                             new Locale("ja"));
    
    public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
              @Override
             public Locale resolveLocale(HttpServletRequest request) {
                if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
                return Locale.getDefault();
                }
                List<Locale.LanguageRange> ranges = Locale.LanguageRange.parse("da,es-MX;q=0.8");
                Locale locale = Locale.lookup(ranges, locales);
                return locale ;
            }
    }
    
    final String headerAcceptLanguage = request.getHeader("Accept-Language");
    
    // check valid
    if (!HttpHeaderUtils.isHeaderAcceptLanguageValid(headerAcceptLanguage, true, Locale.getAvailableLocales()))
        return;
    
    /**
     * Checks if the given accept-language request header can be parsed.<br>
     * <br>
     * Optional the parsed LanguageRange's can be checked against the provided
     * <code>locales</code> so that at least one locale must match.
     *
     * @see LanguageRange#parse(String)
     *
     * @param acceptLanguage
     * @param isBlankValid Set to <code>true</code> if blank values are also
     *            valid
     * @param locales Optional collection of valid Locale to validate any
     *            against.
     *
     * @return <code>true</code> if it can be parsed
     */
    public static boolean isHeaderAcceptLanguageValid(final String acceptLanguage, final boolean isBlankValid,
        final Locale[] locales)
    {
        // allow null or empty
        if (StringUtils.isBlank(acceptLanguage))
            return isBlankValid;
    
        try
        {
            // check syntax
            final List<LanguageRange> languageRanges = Locale.LanguageRange.parse(acceptLanguage);
    
            // wrong syntax
            if (languageRanges.isEmpty())
                return false;
    
            // no valid locale's to check against
            if (ArrayUtils.isEmpty(locales))
                return true;
    
            // check if any valid locale exists
            for (final LanguageRange languageRange : languageRanges)
            {
                final Locale locale = Locale.forLanguageTag(languageRange.getRange());
    
                // validate available locale
                if (ArrayUtils.contains(locales, locale))
                    return true;
            }
    
            return false;
        }
        catch (final Exception e)
        {
            return false;
        }
    }