在Java中解析Accept-Language标头

Pus*_*kar 36 java servlets http-accept-language

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

例如.

Accept-Language : en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2
Run Code Online (Sandbox Code Playgroud)

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

Bre*_*ail 44

我建议使用ServletRequest.getLocales()容器解析Accept-Language而不是试图自己管理复杂性.

  • 除非您计划直接支持所有可能的语言环境,否则ServerRequest.getLocales可能是更好的选择. (4认同)
  • @djmj只需检查相关时是否存在"Accept-Language"标题就足够了.不过,你是对的,新的JDK增加了额外的API,这些API可能很有用(这个答案来自2011年!). (3认同)
  • 问题是如果用户没有提供有效的区域设置,`ServletRequest.getLocales` 会返回服务器区域设置。为了防止语言垃圾邮件请求,您必须自己在 `LanguageRange.parse(String)` 方便的地方解析它。 (2认同)

Qia*_* Li 34

为了记录,现在可以使用Java 8:

Locale.LanguageRange.parse()
Run Code Online (Sandbox Code Playgroud)

  • @Alex:根据javadoc,您不需要对返回的`List`进行排序:"与加权列表不同,优先级列表中的语言范围根据其优先级按降序排序.第一个语言范围包含最高优先级,最符合用户的偏好." 所以你的代码可能只是:`Locale.LanguageRange.parse(requestedLangs).stream().map(range - > new Locale(range.getRange())).collect(Collectors.toList());` (4认同)
  • 如果需要语言环境列表,则可以使用Locale.LanguageRange.parse(requestedLangs).stream()。sorted(Comparator.comparing(Locale.LanguageRange :: getWeight).reversed())。map(range-> new Locale(range.getRange()))。collect(Collectors.toList());` (2认同)
  • 这不会返回正确解析的语言环境,例如,“ en-GB”将被解析为没有国家/地区的“ en-gb”语言。 (2认同)

Pet*_*ter 15

这是解析不需要servlet容器的Accept-Language头的另一种方法:

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());
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到Accept-Language标头和相关q值的说明:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

非常感谢Karl Knechtel和Mike Samuel.对原始问题的评论有助于我指出正确的方向.


Aru*_*run 5

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

在ApplicationConfig.java中这样写

@Bean

public LocaleResolver localeResolver() {
    return new SmartLocaleResolver();
}
Run Code Online (Sandbox Code Playgroud)

我的常量类中有这个列表,其中包含我们支持的语言

List<Locale> locales = Arrays.asList(new Locale("en"),
                                         new Locale("es"),
                                         new Locale("fr"),
                                         new Locale("es", "MX"),
                                         new Locale("zh"),
                                         new Locale("ja"));
Run Code Online (Sandbox Code Playgroud)

并将逻辑写在下面的类中。

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 ;
        }
}
Run Code Online (Sandbox Code Playgroud)