Is it possible to vary page caches (to have cache

2019-05-29 12:41发布

问题:

We have a multilanguage site and want to cache e.g. page /about. English and belarusian pages have the same URL: /about, language is stored in and detected from the cookies.

  • En: /about, cookie: site_lang: en
  • Be: /about, cookie: site_lang: be

We have a ReverseProxy cache (SymfonyHttp or Varnish). When the first user opens the /about page with en value in cookies, it's cached by ReverseProxy and by browser. Response headers:

Cache-Control max-age=600, public, s-maxage=600
Last-Modified Mon, 27 Apr 2015 21:48:34 GMT
Vary X-Language
...

What is X-Language:

Since we can't vary by Cookies (it will lead to have different cache versions for each user because of at least session id), we vary by custom header that is set by Apache.

So when user made a GET request, Apache parses site_lang cookie and adds parsed value to custom header X-Language. With this logic, ReverseProxy knows what to do: just return cache or forward request to application if there is no cache for some language from this header.

It works when the second user opens the /about page with be value in cookies, Apache parses this language, creates X-Language: be header and ReverseProxy don't return cache for en language but forward request to application.

But it doesn't work when the first user tries to change locale with LocaleSwitcher on the site. When it tries to click to another language link, browser immediately returns local cached page and user's request is not processed by Apache, of course.

So my question, how to handle this situation, what are the possible solutions. The main requirement is we don't want to have language in the URL.

Thank you.

回答1:

You can customize what Varnish uses for its hash key in the vcl_hash function, see here.



回答2:

You would need to send a Vary: Cookie to the client because for the client, the response he gets depends on the cookie he sends. This will however not work if there are any other cookies like google analytics.

The other obvious alternative is to use the locale in the domain or the path, so en.mydomain.com/about or mydomain.com/en/about. This is also more friendly when people send links to pages as the language is part of the link.

In case your application is built with symfony, its no problem to change the strategy, and also to have one language that is the "default" and does not have the locale in the URL.