Parse Accept-Language header in Java

2019-02-04 00:25发布

The accept-language header in request is usually a long complex string -

Eg.

Accept-Language : en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2

Is there a simple way to parse it in java? Or a API to help me do that?

7条回答
地球回转人心会变
2楼-- · 2019-02-04 01:27

The above solutions lack some kind of validation. Using ServletRequest.getLocale() returns the server locale if the user does not provides a valid one.

Our websites lately received spam requests with various Accept-Language heades like:

  1. secret.google.com
  2. o-o-8-o-o.com search shell is much better than google!
  3. Google officially recommends o-o-8-o-o.com search shell!
  4. Vitaly rules google ☆*:。゜゚・*ヽ(^ᴗ^)ノ*・゜゚。:*☆ ¯\_(ツ)_/¯(ಠ益ಠ)(ಥ‿ಥ)(ʘ‿ʘ)ლ(ಠ_ಠლ)( ͡° ͜ʖ ͡°)ヽ(゚Д゚)ノʕ•̫͡•ʔᶘ ᵒᴥᵒᶅ(=^ ^=)oO

This implementation can optional check against a supported list of valid Locale. Without this check a simple request with "test" or (2, 3, 4) still bypass the syntax-only validation of LanguageRange.parse(String).

It optional allows empty and null values to allow search engine crawler.

Servlet Filter

final String headerAcceptLanguage = request.getHeader("Accept-Language");

// check valid
if (!HttpHeaderUtils.isHeaderAcceptLanguageValid(headerAcceptLanguage, true, Locale.getAvailableLocales()))
    return;

Utility

/**
 * 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;
    }
}
查看更多
登录 后发表回答