故事
离四点还有一个小时,还有个批量回复的功能没有做完,自从上次被夸了之后,在项目的估时上面尽可能地压缩时间,希望能够更快完成任务,然后提交上线,但是,估计这一次,还是不行,周会不去开了。
后台写完,跑了测试用例,功能基本上就是我要的了,现在就差Web层的逻辑和前台的页面以及js。其实最讨厌写的还是前台的页面,逻辑,莫名其妙会花很长的时间,即使只是调整一些样式,拼装一些数据,在大前端,前后端分离的背景下,这已经是最低级的活儿。但是还是要得把整个功能给做完,至少自己还是能够控制住的。
把之前单个提交的html代码拿过来,建了一个新的html文件,在后台web层写了一个方法跳转到这个html页面。html页面的样式也很简单,就是一个简单的form表单。
<form class="form" action="" method="post" id="human">
id:<input name="id" id="id"/><br/>
名字:<input name="name" id="name"/><br/>
年龄<input name="age" id="age"/><br/>
<button type="submit" id="subBtn">提交</button>
</form>
既然贴了html,接着就是用js组装数据,然后使用ajax提交到后台。继续贴代码呗。
$(function(){
var postNotSupport = {
init: function() {
this.initEvent();
},
initEvent: function() {
var _this = this;
// post not support
// _this.postNotSupport;
},
postNotSupport: function() {
var _this = this;
_this.saveAjax();
},
saveAjax: function() {
var human = {
id:$("#id").val(),
name:$("#name").val(),
age:$("#age").val()
}
$("#subBtn").on("click", function() {
$.ajax({
url:"/postNotSupport/save",
type:"post",
contentType:"application/json",
data:JSON.stringify(human),
sync:true
});
})
}
}
postNotSupport.init();
})
后台是使用SpringMVC去接的,
@RequestMapping(value = "/postNotSupport/save", method = RequestMethod.POST)
@ResponseBody
public Response save(@RequestBody Human human) {
System.out.println(human);
return Response.success();
}
完事具备,就等调试了。可是,让我想不到的一幕竟然出现了,当我点击提交的时候,出现了‘POST’ not support的错误,经验告诉我,这个错误和POST的关系几乎为0,因为没有一个人会犯一个前台是POST提交的方式,而后台确实用GET去接受的错误,而且这个错误实在是太容易发现了。(后面就是我的打脸时刻),再按照以往的经验,如果出现这个错误,那么一定就是后台报的错,我只需要看后台报错的异常堆栈信息,就可以解决了。
以往的经验,在一定的程度上,是可以帮助人的,但是在绝大多数的情况下,都是坑人的。经验真的就像一个圈圈一样,把你画到圈圈里面,然后就只能够看到圈圈里面的东西,外面的东西就看不到,颇有一叶障目不见泰山的感觉。
我继续往下拉异常的信息,可以,让我发慌的事情出现了,后台就只抛了POST not support的异常,往下的就是一些sql语句信息,很郁闷,心里想着,不科学吧。看了下时间,已经是四点半了,周会已经开了半个小时,不知道他们的色眼看人看得怎么样。不去想了,五点前解决问题,然后上线吧。
在web层打了一个断点,跑去页面重新又试了一下,idea的黄色闪动亮起,我知道,这时候的程序在这个断点下停下来。切换到idea,红色的高亮如期而至,看了下接受的数据信息,从前台发过来的json,在后台都转换成的对象,这时候还没有报错。继续向下执行,程序进入到了Service层的方法,同时,那个可怕的错误也开始显现,继续运行,DAO层插入数据,返回前台,一切都很顺利,除了那500的错误,那个post not support。
既然后台没错,那就去前台的js排查吧,在ajax前面和后面的位置上打上debugger的标准,让程序在相关的地方停下来,当js运行到第一个debugger的时候,一切都相安无事,当运行到第二个debugger的时候,数据还没有返回到前台,异常就出现了。叹了口气,看了下时间,已经是5点,估计是发不了版了,如果失败了,还得麻烦运维他们,而且周末也来了,在这个节骨眼上,还是不发布吧,线上还运行着一个正常的版本,而且这个版本还运行得挺好的。于是,自己放松下了神经,也许卸下压力,可以让自己能够排查出问题来。
打开百度,骂了一声,其实百度的搜索质量一般般,奈何用不了翻墙的软件,就暂时用百度吧。百度的搜索结果,基本上都千篇一律,某一篇博文出来,复制了一次又一次,所以即使点击去十几个链接,内容基本都一样。上面讲的如果是json返回,需要加@ResponseBody
,method的get方法和post方法要写清楚,诸如此类的,我都一遍又一遍地检查,什么都是按照流程来的,应该不会有错。
灵光一闪,想想百度坑人的事情,想想网络上99%的都是错误的,只有1%的是不一定是对的原则。我默默打开官网,spring的官网,真TM慢。等了半天,加载出来了,找到SpringMVC的内容,看了下的例子,啊,为什么一毛一样,都能够出错???心里一万个问号,同时有一万个草泥马在奔跑。时间来到五点半,他们开会也回来了。胖子回来,喝了口水,我心里嘀咕着,“那个上不了线了,我还在处理,还没开发完,周一上吧”,胖子点了点头表示同意。
继续debug,怎么还继续下去!!!只能求救呀!!!
拍了拍胖子的桌面,说我遇到了一个post不支持的错误,问怎么解决。呃,好吧,受到了无情的嘲讽,post不支持,你是用post去提交get请求了吧。我据理力争,ajax和后台都是post的。不可能出现不对应的情况。这时候,由于微信的上线,boss去忙其他的
嘿,大芳,你解决过post不支持的问题吗?大芳轻蔑一下,你是不是用post去提交get请求了,来来来,打开代码,让我看看,作为部门后台开发的唯一一名女将,多少有点王者风范。你把这个{}去掉,嗯,去掉,跑一遍,错误还是如期而至,你这个用PostRequest吧,改掉,跑一遍,呵呵。然后我按照我一开始的debug流程,又跑了一遍。
解决不了,就只能等待。
时间到了8点半,我已经很绝望地坐了4个小时了,这4个小时,我都在处理这个虚无缥缈的bug,仿佛一切都不顺利,我到底做错了什么。胖子忙完其他的事情,招呼过来,坐下,开始debug,同时,也围过来一群同事,在讨论这个问题。
事情并没有预想的一样,胖子坐下,扫了一下代码,说你这个少了个分号,然后拂袖而去,不留姓与名。他还是按照异常的堆栈信息,一个断点一个断点打进去,打到最后一个类是DispatcherServlet,这是SpringMVC的内容分发器,前台所有的请求都会经过这个类进行分发。ajax请求了一次,往后台提交了一份数据,理论上,后面如果没有其他的操作,这个请求就停止了,也就是没有其他的请求会进来。但是,却进来了一个页面的POST请求。
原因已经知道了,就是这个页面的POST请求,但是,他是怎么触发的,找到这一步,又一次陷入了迷茫,围过来的一群人都不知道怎么回事。继续处理,在相关的POST请求上打上断点,但是这个断点并没有进来,说明ajax请求之后的转发并不是后台处理的,原因就只有在前台上。
看了一遍又一遍的js文件,看不出有什么问题,大家都陷入了绝望的时候,大宏将了句,会不会是html的问题,胖子急忙去找html文件,看到那个form表单,似乎明白了点什么,“你这个form表单,也提交了一次吧?”,他把form相关的内容注释掉,只留下input,再请求一次,这个bug就没有出现了。
时间已经到了9点10分,经过了5个多小时,这个未知bug终于是定位到了。
可是为什么在原来的页面上,html文件也是这么写的,却没有出现这个异常的信息?
$(function(){
var postNotSupport = {
init: function() {
this.initEvent();
},
initEvent: function() {
var _this = this;
// 提交成功
_this.validPost();
},
validPost: function() {
var _this = this;
$("#human").validate({
submitHandler:function(form){
_this.saveAjax();
return false;
}
});
},
saveAjax: function() {
var human = {
id:$("#id").val(),
name:$("#name").val(),
age:$("#age").val()
}
$("#subBtn").on("click", function() {
$.ajax({
url:"/postNotSupport/save",
type:"post",
contentType:"application/json",
data:JSON.stringify(human),
sync:true
});
})
}
}
postNotSupport.init();
})
答案就在js文件上面,原来的js是有做字段规则校验的,使用jquery validate的submitHandler方法提交表单,而且还写了个return false的语句,这个return语句,正是jquery阻止浏览器默认行为的方法,也就是说,阻止了form表单的submit方法。呀,坑死了。以前的项目写法真多样,一个项目里面表单提交,ajax提交的基本都混杂着,真是坑人的混杂。
不管,吃饭去。几个小时的debug,加上花椒油,真的身心疲惫,真不想讲话。
代码
感悟
- 项目规范很重要!!!html的写法,js的写法,java的写法都要按规范了,提交表单要不用submit,要不用ajax,混合双打反而是坑了自己坑了后面的人;
- 写后台的太注重逻辑了,基本上debug都是集中在java和js文件,而html文件只会认为是一个页面样式,不会出岔子,而这次却出了岔子;
- debug要整个流程跟下来,从前台的页面,js,到后台的controller层,service层,dao层,都要跟;
- 如果解决不了,就不要钻牛角尖,问下别人,或者喝个茶放松下;
- 框架的原理需要清楚,至少也要了解,这样更容易排错。