【问题标题】:Varnish: How to change language of the site based on a cookie?Varnish:如何根据 cookie 更改网站的语言?
【发布时间】:2014-09-10 10:49:39
【问题描述】:
我的网站几乎可以正常工作了。它适用于一种语言,但我有一个设置语言的 cookie。我也散列了。
问题是我无法更改 cookie 的值,我不知道该怎么做。
我的网站收到一个名为“lg=1”的变量,其中“1”是语言代码。
我不知道如何将其传递给我的网站,以获取“英文”版本并再次保存新 cookie(具有 lg=1 值),因此下次用户访问时不使用 lg=1 变量,他根据 cookie 值访问了我们的英文网站。
有人可以帮助我吗?
谢谢你
【问题讨论】:
标签:
cookies
varnish
varnish-vcl
【解决方案1】:
如果您希望能够根据 get-parameter 设置 cookie,您有两个选择
- 使用 javascript 设置 cookie。 Here is a SO answer for setting Cookie with JS
-
将 Varnish 配置为始终将包含“lg=”的请求传递给您的应用程序,以便您可以在那里设置 cookie。
sub vcl_recv {
if (req.url ~ ".*lg=") {
return (pass);
}
#Your other code in vcl_recv.....
}
【解决方案2】:
您可能需要编辑您的 VCL 文件,默认情况下类似于 /etc/varnish/default.vcl
当您收到语言参数时,您可以通过 Varnish 设置 cookie。
然后使用cookie的值覆盖到后端的请求url。
应该是这样的:
sub vcl_recv {
// Use the value of the cookie to override the request url.
if (req.http.Cookie ~ "lg") {
set req.url = req.url + "?" + req.http.Cookie;
}
// Go to VCL_error to redirect and remove the parametter.
if (req.url ~ "(?i)lg=1") {
error 802 "Remember to use the english version";
}
}
sub vcl_error {
/* Removes lg parameter and remember the english choice */
if (obj.status == 802) {
set obj.http.Set-Cookie = "lg=1; domain=." + req.http.host + "; path=/";
set obj.http.Location = req.http.X-Forwarded-Proto + "://" + req.http.host + regsub(req.url, "\?lg=1", "");
set obj.status = 302;
return(deliver);
}
}
我更愿意为每种语言使用不同的子域,例如,您可以在收到参数时将用户重定向到子域。通过这样做,您不需要每次都覆盖 request.url。
【解决方案3】:
我将使用以下方法来实现:
- 检查 lg cookie 是否存在。如果不存在,则使用后端服务器或清漆服务器进行设置。
- 我更喜欢使用 varnish 而不是后端服务器来设置语言 cookie,以避免后端服务器上的过多请求/负载。
- 默认语言选择必须是英语,即“1”
-
根据用户语言选择设置哈希值。这将有助于维护基于语言的不同缓存以及从缓存中检索数据。
请参考以下代码:
我使用了 IPD cookie。
backend default {
#applicable code goes here
}
sub identify_cookie{
#Call cookie based detection method in vcl_recv
if (req.http.cookie ~ "IPD=") {
set req.http.Language = regsub(req.http.cookie, "(.*?)(IPD=)([^;]*)(.*)$", "\3");
}
}
C{
#used to set persistent(9+ years) cookie from varnish server.
const char* persistent_cookie(char *cookie_name){
time_t rawtime;
struct tm *info;
char c_time_string[80];
rawtime = time(NULL) * 1.2; /*Added 9 years*/;
info = localtime(&rawtime);
strftime(c_time_string,80,"%a, %d-%b-%Y %H:%M:%S %Z", info);
char * new_str ;
if((new_str = malloc(strlen(cookie_name)+strlen(c_time_string)+1)) != NULL){
new_str[0] = '\0'; // ensures the memory is an empty string
strcat(new_str,cookie_name);
strcat(new_str,c_time_string);
} else {
syslog(LOG_INFO,"Persistent cookie malloc failed!\n");
}
return new_str;
}
}C
sub vcl_recv {
call identify_cookie; #Used to get identify cookie and get its value
if(!req.http.Cookie ~ "IPD"){
C{
VRT_SetHdr(sp, HDR_REQ, "\006X-IPD:",persistent_cookie("IPD=1; domain=yourdomain.com; path=/; Expires="),vrt_magic_string_end);
}C
}
}
sub vcl_fetch {
set beresp.http.Set-Cookie = req.http.X-IPD; #used for debug purpose only.Check cookie in response header
}
sub vcl_backend_response {
#applicable code goes here
}
sub vcl_deliver {
#applicable code goes here
set resp.http.X-Cookie = "Cookies Set ("req.http.X-IPD")"; #used for debug purpose only.Check cookie in response header
}
sub vcl_error {
#applicable code goes here
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
}
if(!req.http.Language){
req.http.Language = 1 #default english language
}
hash_data(req.http.Language); # make different hash for different language to avoid cache clashing
return(hash);
}
sub vcl_pipe {
#applicable code goes here
}
sub vcl_pass {
#applicable code goes here
}
注意:请确保只更改cookie名称。正则表达式支持从多个cookie中检索cookie值而不考虑其顺序