简体   繁体   中英

How to use single tomcat instance with multiple domains behind nginx for i18n

I have a Spring MVC Application on tomcat (8080) behind nginx proxy server. Also I have 3 different domains:

  1. www.mywebsite.com for English
  2. www.mywebsite.de for German
  3. www.mywebsite.fr for French

Now I have to make sure that, when the user goes to www.mywebsite.de , the language of the site has to be German , *.com should be English and so on.

So how can I achieve this with single tomcat instance ?


I could start three tomcat instances:

  1. localhost:8080 with default locale 'DE'
  2. localhost:8081 with default locale 'EN'
  3. localhost:8082 with default locale 'RU'

Then in my ngnix configuration I would forward all requests via proxy_pass in this way:

  1. domain.de -> localhost:8080
  2. domain.com -> localhost:8081
  3. domain.ru -> localhost:8082

This means I have to maintain 3 tomcat instances. Thats why this question.

Application under tomcat need to know which language it needs to serve. How are you doing that? – Sangram Jadhav Jun 6 at 7:12

@SangramJadhav over Locale and ?lang=en – dit Jun 7 at 18:21

So, then you can just use nginx to modify the requests prior to them being proxied over to your application in tomcat, to add the extra ?lang=XX , depending on the domain name that's being accessed.

The map directive is probably most appropriate here to do the mapping between the domains and the languages:

map $http_host $lang {
  hostnames;

  default       en;

  example.de    de;
  *.example.de  de;
  example.at    de;
  *.example.at  de;
  example.fr    fr;
  *.example.fr  fr;
  example.cd    fr;
  *.example.cd  fr;
  example.ru    ru;
  *.example.ru  ru;
  example.by    ru;
  *.example.by  ru;
}

Subsequently, you just add this to every request handled through the proxy_pass directive with $uri and $args :

proxy_pass http://127.0.0.1:8080$uri?$args&lang=$lang;

Note, however, that using variables in proxy_pass will turn off the proxy_redirect feature from its default of default , so, you might also have to add something like this to your config:

proxy_redirect http://127.0.0.1:8080/ /;

Also, if you use proxy_cache , you might have to amend the proxy_cache_key .

Setting the locale for a spring mvc should have nothing to do with your servlet container (tomcat) or proxy (nginx). Spring is the one managing all this.

Check out this example http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/

One reason you don't want to have application logic like this at the server level is it will make scaling much harder. No matter what you'll need to create a mapping file for TLD to Locale. And for each mapping you need a language file. When you add another locale it would easier to just redeploy a single app vs a proxy and an app.

If you map TLD to server you'll have to create a scaling group for each language. Then you might end up with a bunch of nodes sitting idle doing nothing while having a bunch with a load serving a single language. If you're running in something like AWS you'll end up with higher monthly bill.

It also complicated both local dev along with deployments. Life is much better when you just have a single app. If you supported 10 languages you should have to do 10 deploy as each app would need a different param to start to set the default locale.

If you wanted to make the locale based off the domain TLD you could extend SessionLocaleResolver . See source

In an app I'm working on I use spring's CookieLocaleResolver

@Bean
public LocaleResolver localeResolver() {
    CookieLocaleResolver resolver = new CookieLocaleResolver();
    resolver.setDefaultLocale(Locale.ENGLISH);
    return resolver;
}

You just need to do implement LocaleResolver . You can get the TLD from HttpServletRequest. Then it's just a matter of returning the correct Locale based on your rules.

ok the current solution is to override your LocaleResolver . It is not my favorite because I have to extend the code every time if I add new TLD. But anyway, here is an example:

public class CustomCookieLocaleResolver extends CookieLocaleResolver {

    private static final Locale      LOCALE_RU      = new Locale("ru");
    private static final Set<String> UNDERSTAND_RU  = new HashSet<>(Arrays.asList("ru", "be", "kz", "uk"));

    @Override
    protected Locale determineDefaultLocale(HttpServletRequest request) {

        Locale locale = getLangByHostName(request);

        if (locale == null) {

            // Header: Accept-Language or server default locale
            String lang = request.getLocale().getLanguage();

            if (Locale.GERMAN.getLanguage().equals(lang)) {
                return Locale.GERMAN;
            } else if (UNDERSTAND_RU.contains(lang)) {
                return LOCALE_RU;
            }
        }

        return Locale.ENGLISH;
    }

    private Locale getLangByHostName(HttpServletRequest request) {

        String host = request.getServerName();

        if (host.endsWith(".de")) return Locale.GERMAN;
        if (host.endsWith(".ru")) return LOCALE_RU;

        return null;
    }

}

I believe it is also possible to override Accept-Language header dependent on TLD on the nginx / proxy level.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM