ajax调用接口数据错乱的原因及解决方法

        前段时间在做项目的时候遇到一个问题,在开发webapp的时候使用ajax调用后端接口的时候,出现了接口数据错乱的问题,现在总结一下

问题描述:

        同一个页面同时调用多个接口:A、B、C、D、E,正常返回结果应该是A-a, B-b, C-c,D-d,E-e。在网络环境比较好的时候,没有问题,然而,在网络环境比较差的时候,错误出现了。返回结果中至少有两个接口返回的结果被其他接口的数据覆盖,结果变成了A-a, B-c, C-c,D-e,E-e,或者A-b, B-b, C-b,D-d,E-e ...... 结果被覆盖的情况完全随机,每次都可能不一样,相同的是每次都会错乱。

        当时第一反应是前端ajax并发导致数据错乱,因为之前自己写PC端和移动端网页的时候(对,不称职的全栈就是我)调用的接口是一样的,没有出现过类似的问题,而现在的webapp是由新入职的前端小哥(不是小白,是资深前端)来做的,新人来了,出现新的问题,那一定是新人这边的问题,所以果断甩锅过去。

        结果前端小哥表示自己也是首次遇到同样的问题,找了很多资料也百思不得其解,我也认为这肯定是前端的问题就没有细查,这个问题就一直悬而未决,直到我忙完了其他事情,前端小哥还没有找出问题,没法海得我自己来了。

开始定位问题

        问题在前端,那就从前端开始,写一个测试页面,请求路径为我们的测试服:

ajax调用接口数据错乱的原因及解决方法_第1张图片

查看控制台,结果:错乱,和之前的错误预估一样,网络环境差的时候,数据错乱

没有对比就没有发言权,所以这次把请求路径变为自己的开发环境:

ajax调用接口数据错乱的原因及解决方法_第2张图片

查看控制台,结果竟然还是错乱,这个问题首次在本地重现了,ok,至少进了一步。

再看看是不是偶然事件,于是多刷新几遍,结果无一例外的全部是数据错乱

之前直接甩锅到前端,因为前端用的框架和我之前用的框架不一样,为了确定是不是框架的原因,我特意直接用jQuery写ajax调用接口,看来框架的原因可以排除了

排除了前端的问题,那就是后端接口的问题了,然后我开始查接口的实现方法,突然发现一个可能的问题,后端使用SpringMVC,所有接口都继承自同一个Controller

......
......
/**
 * 通用工具类
 * @author heh
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class BaseController {
	
	......
	......
	
	/**
	 * 提示(用于返回操作结果)
	 */
	protected Tip tip = new Tip();

	......
	......	
}

然后所有的接口都统一使用这个tip作为数据容器然后返回数据,是这样写的

......

@Controller
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
public class WSControllerImpl extends BaseController implements ...... {

	......

	@Override
	public Tip getUserMessage(HttpServletRequest req) {
		String messageid = req.getParameter("id");
		tip.success(userService.getMessageById(messageid));
		return tip;
	}
	
	......

}

之前为了减少重复代码,就把这个tip容器放到了BaseController里,供其子类调用,没有考虑到不同接口调用这个公共参数的时候,不是独占调用,而是所有的接口都可以修改,所以多个接口同时调用的时候,就会出现A接口调用完毕,还没有返回的时候,tip已经被B接口修改了,所以造成A接口返回的数据和B接口返回的数据变成一样的情况。至此确定了问题。

问题确定之后,解决就简单了,只要让每个接口的tip单独new出来即可,不使用公共资源

回顾确定问题的过程,发现多接口并发执行的时候,少于4个接口的时候不会错乱,大于或等于4个接口的时候,问题必然出现。这也算是一个低级错误了。


总结:在多个子类访问同一个父类的资源的时候,数据类资源最好是不可更改的类型,不要让多个子类同时修改父类的内容。父类的公用内容尽量使用工具操作类的代码,不要用数据共享的内容。代码还是要踏踏实实写,偷懒很容易出问题。


你可能感兴趣的:(java)