3年前写的在HttpModule中记录访问日志的代码,在最近使用日志数据分析登录账号的IP情况时,才发现了一个不易重现的BUG——日志中记录的登录账号出现串掉的情况。之所以这个时候才发现该问题,是因为部分用户的IP是固定的,但是日志里却出现了别人的IP。而之所以3年后才发现,是因为这块日志数据一直没怎么用过。回头想想,根本原因还是在用成员变量的时候没考虑到多线程的情况,或者说多用户同时访问的情况。因为HttpModule里的事件,是所有页面实例共用的。
问题代码:
string dateBeginRequest;//开始请求时间
string userName;//用户名 public void Init(HttpApplication application)
{
application.AcquireRequestState += (new EventHandler(this.Application_AcquireRequestState));
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
application.EndRequest += (new EventHandler(this.Application_EndRequest));
}
实现System.Web.IHttpModule的类中,有两个导致BUG的字符串成员变量。其中字符串成员变量dateBeginRequest在Application_BeginRequest事件方法中赋值,字符串成员变量userName在AcquireRequestState 事件方法中赋值,值来源于Session。当在本地调试时很难重现用户A的账号记录到用户B的日志数据中,这种情况。但是当生产环境有一定的并发请求的时候,就会出现用户A的账号记录到用户B的日志数据中,日志数据中请求开始时间这个字段也会出现同样的问题。
解决办法就是把这部分记录请求日志的代码,转移到各页面的基类中,因为各页面的后台类实例是独立的,互不影响。
上述问题在我们写的基于Servlet的Java开发框架中也出现了,解决办法是在方法内部创建对象实例,而不是使用类的成员变量来赋值再使用。之所以Servlet中成员变量也会出现该问题,是因为Servlet的service等方法也是所有映射到的请求都会进入该方法,存在并发的情况。
本文首发于我的CSDN博客:https://blog.csdn.net/n_ithero/article/details/104062423