varnish配置内嵌C语言时间处理
公司网站有很多用到取服务器时间的jsonp请求,比如限时尊抢每天准时11点上线,就需要用ajax请求取服务器时间。此功能简单且访问量较大,因此决定将该ajax请求后端服务器的功能迁到varnish里。感谢varnish的vcl语言对应内嵌C功能,使得我们可以在varnish截获请求并反馈回当前时间即可。整个功能比较简单,设计思路是这样的,在vcl中的vcl_recv里截获到对服务器请求时间URL的访问,直接error回一个自定义的statuscode,此处最好用扩展的statuscode(用http协议里的状态值也可以实现,但是需要在response里做标记以便在vcl_error返回之前做判断),代码片段如下:
sub vcl_recv {
##略去其他配置
if (req.url ~ "(?i)/xxxx/GetTime.aspx" ) {
error 606 "mark";
}
##略去其他配置
}
然后在vcl_error里捕捉这个error并计算时间,然后输出。代码如下:
sub vcl_error {
###注意此处判断我们自定义的Status Code
if (obj.status == 606){
###注意将最终Deliver的状态转化为200
set obj.status = 200;
set obj.response = "OK";
C{
static void *reg;
VRT_re_init(®, "(?i)/xxxx/gettime.aspx\\?callback=");
char *callback = (char*)VRT_regsub(sp, 0,VRT_r_req_url(sp),reg, "");
char buf[30];
time_t clock = time(NULL)+28800;
struct tm *tm = gmtime(&clock);
strftime(buf,sizeof(buf),"%Y/%m/%e %T",tm);
char json[strlen(callback)+33];
char *prefix = strcat(callback, "({\"timer\":\"");
strcpy(json,prefix);
strcat(json,buf);
strcat(json,"\"})");
VRT_re_fini(reg);
VRT_synth_page( sp, 0, json, "", "", "", vrt_magic_string_end) ;
}C
return(deliver);
}
Okay,这样就搞定。
下面再说一下这个版本之前的一个问题。
由于用到了C的时间处理函数(本人没有写过C程序,用起来还是挺费劲的:),各路C高手勿拍板砖哈:)),在最初版本中遇到了一个令人汗颜的问题。
为了能支持不同的时区设置的服务器,因此用到了取gmt时间的函数,同时将此时间+8个小时转换为北京时间,在做这个转换时用到的代码如下:
time_t clock = time(NULL);
struct tm *tm = gmtime(&clock);
tm->tm_hour += 8;
此转换在北京时间0~8点之间工作会出现严重的异常。(想想自己是个C语言盲,习惯了C#代码,轻信了tm结构的文档),没有多想在GMT时间16:00~24:00时会得到tm->tm_hour大于24的情况,导致取得的时间格式错误。
想想真后怕,也算是给自己提个醒吧。