请求中的accept-language标头通常是一个很长的复杂字符串 -
EG。
Accept-Language : en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2
有一种简单的方法可以在java中解析它吗?或者API可以帮助我做到这一点?
答案 0 :(得分:41)
我建议使用ServletRequest.getLocales()
让容器解析Accept-Language,而不是试图自己管理复杂性。
答案 1 :(得分:33)
对于记录,现在可以使用Java 8:
Locale.LanguageRange.parse()
答案 2 :(得分: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());
}
您可以在此处找到Accept-Language标头和相关q值的说明:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
非常感谢Karl Knechtel和Mike Samuel。对原始问题的评论有助于我指出正确的方向。
答案 3 :(得分:3)
ServletRequest.getLocale()
肯定是最好的选择,如果它可用而不是像某些框架那样被覆盖。
对于所有其他情况,Java 8提供Locale.LanguageRange.parse()
,如之前提到的Quiang Li。但是,这仅返回语言字符串,而不是语言环境。要解析语言字符串,可以使用Locale.forLanguageTag()
(自Java 7起可用):
final List<Locale> acceptedLocales = new ArrayList<>();
final String userLocale = request.getHeader("Accept-Language");
if (userLocale != null) {
final List<LanguageRange> ranges = Locale.LanguageRange.parse(userLocale);
if (ranges != null) {
ranges.forEach(languageRange -> {
final String localeString = languageRange.getRange();
final Locale locale = Locale.forLanguageTag(localeString);
acceptedLocales.add(locale);
});
}
}
return acceptedLocales;
答案 4 :(得分:3)
我们正在使用Spring启动和Java 8.这是有效的
在ApplicationConfig.java中写这个
@Bean
public LocaleResolver localeResolver() {
return new SmartLocaleResolver();
}
我在我的常量类中有这个列表,它有我们支持的语言
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 ;
}
}
答案 5 :(得分:1)
上述解决方案缺乏某种验证。如果用户未提供有效的语言环境,则使用ServletRequest.getLocale()
返回服务器语言环境。
我们的网站最近收到了各种Accept-Language
heades的垃圾邮件请求,例如:
secret.google.com
o-o-8-o-o.com search shell is much better than google!
Google officially recommends o-o-8-o-o.com search shell!
Vitaly rules google ☆*:。゜゚・*ヽ(^ᴗ^)ノ*・゜゚。:*☆ ¯\_(ツ)_/¯(ಠ益ಠ)(ಥ‿ಥ)(ʘ‿ʘ)ლ(ಠ_ಠლ)( ͡° ͜ʖ ͡°)ヽ(゚Д゚)ノʕ•̫͡•ʔᶘ ᵒᴥᵒᶅ(=^ ^=)oO
此实现可以针对受支持的有效Locale
列表进行可选检查。如果没有此检查,"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;
}
}
答案 6 :(得分:0)
Locale.forLanguageTag("en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2")