记录下做项目(在线考试系统)遇到的问题

1.使用post提交url不隐藏参数的问题

注册功能,表单采用ajax提交时。指明post提交还是会出现url参数未隐藏。但是数据成功被提交到了数据库。
排查发现是注册这个按钮的问题。

<button id="register">注册</button>

如果用a链接标签

<a href="javascript:;"  id="register">注册</a>

一切正常
为什么呢?因为button默认是type=sumbit,包括input提交按钮也是。如果类型为submit,那么点击时就会提交表单。所以将button标签或者input添加一个type属性,设置为button即可

ajax提交表单时,按钮类型应该是button,不能是submit。

2.引入bootstrap样式无效果

引入bootstrap路径正确通过127.0.0.1:3000/index.html发现无样式。本地文件打开正常。
查看控制台报错如下
Refused to apply style from 'http://localhost:3000/node_modules/bootstrap/dist/css/bootstrap.min.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
是因为通过npm安装的bootstrap安装到了node_modules文件夹下。而我在入口文件中启用静态资源,只是默认的public文件下。所以由于静态资源访问限制导致。
所以可以添加app.use(express.static(path.join(__dirname, 'node_modules')));
或者将bootstrap的文件拷贝到public下

3.mysql多表的同步问题

mysql进行表的同步问题
创建触发器
https://blog.csdn.net/qq_21891743/article/details/85061495
https://www.jb51.net/article/35123.htm

CREATE <触发器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<触发器主体>

创建插入触发器

create trigger studentInsert after insert
on user for each row
begin
INSERT INTO student(username,password) VALUES(new.username,new.password);
END;

反之亦然

create trigger userInsert after insert
on student for each row
begin
INSERT INTO user(username,password) VALUES(new.username,new.password);
END;

但是出现问题了。修改A表,B表可以同步。但是修改B表,A表不改变。而且还不能相互都加触发器。暂时不知道怎么解决

或者是设置连接字符串的配置时,添加属性multipleStatements: true。默认是关闭,只能执行一条。
今天想起来以前学的细节点的数据库内容。印象中和外键可能有关。有空查

4.文件引入顺序

在做数据列表渲染时。导jquery文件放在了js文件后。导致出错。

5.mysql [Err] 1054

前期使用的json接口。在进行ajax请求时,一直路径不对。网上查,都是使用restful接口的。但是改了后还是不对,最后发现后台返回的设的标志位为2.也就是没影响到行数。去MySQL中查看,数据并未发生改变。将语句单独取出在MySQL中运行。神奇的是,个别能成功。个别不成功,这时候就会返回标志位为2。
报错如下[SQL]delete from student where username=sad [Err] 1054 - Unknown column 'sad' in 'where clause'
猜测是关键字或是字符格式问题,导致。
修改全为数字才成功。
但是又发现有几率出错。未解决

6.request请求的req.body、req.params、req.query区分

关于req.body、req.params、req.query
首先req.params,req.query是用在get请求当中,而req.body是用在post请求中的。
而req.params,req.query的区分粗略查了下没明确说明。有空查官方文档。

7.请求后服务器返回两次或者两次以上的响应

在做文件上传下载有这么个错误。上传成功,但是重定向回上传的页面。服务器就终止报错了。
在这里插入图片描述
Cannot set headers after they are sent to the client
查了资料。
怎么回事呢?
是由于在一次请求后服务器返回两次或者两次以上的响应。
因为我在res.redirect没有return声明的情况下进行调用,所以此后函数也立即被调用。
更详细了解的话可以看此处:https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client

8.(大坑)文件下载的文件

postman插件测试正常。能得到文件。但是在进行前端渲染时。ajax请求会进入error。
通过表单里的按钮,可以第一次ajax请求通过id拿到存储的文件信息。但是在进行二次ajax时,会发现一直进入error。查看后台,发现文件名是拼接正确的。虽然中文会有编码错误导致路径不对而失败。但是纯英文的路径正确仍然是进入erro下载失败。
在这里插入图片描述
在这里插入图片描述
废了不少功夫,解决了。详细另开新篇。

9.(小坑)Failed to lookup view “/login.ejs” in views directory “views”

在这里插入图片描述

10.暂搁 sessionid在火狐的问题。

做完用户的状态后。测试发现。在谷歌以及edge均无问题。而在火狐中出现情况就是登陆成功后,在点击跳转其他页面,就会被打回登陆页面。查看发现火狐不知道为什么访问其他页面先访问了登陆的虚拟路径。由于我设置当回到登陆页面将sessionid销毁,就会导致以上情况。其余浏览器正常。

11.使用jquery时.html()、.text()、.val()的不仔细

都知道这三种各有各的含义。
在做分页跳转时,将前台的点击的页数值获取传到后面。由于错误使用导致整体逻辑写完后驳回。再分一步步回顾时,发现ejs模板也是写错了一点。
应该一步步确保每步都确定得到自己想要的结果后,再往下。这次想一蹴而就就导致了问题。

12.req.query、req.body和req.params的区别

get请求是使用req.params、req.query。 post请求是req.body

而且req.params是用于restful接口的对应路径形式http://localhost:3000/books/book/1
而传统urlhttp://localhost:3000/toEditBook?id=1则是req.query获取

另外req.body是需要用到body-parser第三方中间件。
补充,如果是restful的put请求,也是req.body

经过仔细排查。发现问题。首先是使用ajax传递页数page和每页数量pigeSize时。传递过来的参数。不是整形。没有经过Number.parserInt()处理。使得在插入sql语句时,值不对(NaN)。
还有就是使用了get请求req.params并没有得到传递过来的值。改用req.query才获取到。
大体上,get请求使用req.query和req.params来获取数据。而post请求使用req.body。而像其他的第三方包比如multer获取到文件信息就是req.files。那么req.query和req.params的区别是什么呢?
虽然两者都是get请求。但是不同的是req.query获取到的url是传统的url风格。比如http://localhost:3000/?id=10。而req.params则是restful接口风格的url,比如http://localhost:3000/10
之前写的一些get请求的接口,在路由处理时风格我都是使用的restful接口的url。

router.get('students/student/:id',(req,res)=>{

})

所以是使用req.params正确获取到url参数。而在补充分页时,我写的

router.get('students/count',(req,res)=>{

 })

所以这里应该是req.query。就是这个细节,导致第一次尝试的失败。好在排查也解决了

13.ajax异步文件上传

在开始,这个上传还是很简单的。只需要借助multer中间件就可以完成。使用的表单提交方式,但是问题还是来了。经测试,没有上传成功的提示普遍用户体验不良好。行吧,那就改ajax。
但是ajax表单提交也没那么简单。对于文件上传来说,有一个坑。最后查了许多资料。通过FormDate对象的使用解决了问题。

14.(大坑)数据库操作顺序问题

今天在优化时,想要处理上传文件同步到数据的信息重复问题。做了个判断,先查找已有的,如果重复就删除,然后再插入。但是在写完代码后,进行测试。发现了问题。

let filename = fileList[i].originalname
                // console.log(filename);
                let checksql = 'select * from homework where filename=? and username=?';
                let checkdata = [filename,username];
                db.base(checksql,checkdata,(result)=>{
                    //有就删除  注意这里之所以写重复是因为会将if条件外的先执行,再执行if里面的。也就是说先插入再删除。应该说是删除相应的db函数里的代码最后执行
                    if(result.length != 0){
                        // console.log('查到'+result.length+'条'+filename);
                        let deletesql = 'delete from homework where filename=? and username=?';
                        let deletedata = [filename,username];
                        db.base(deletesql,deletedata,(result)=>{
                            //删除同username同filename数据
                            let sql = 'insert ignore into homework set username=?,name=?,description=?,filename=?';
                            let data = [username,info.name,info.description,filename];
                            db.base(sql,data,(result)=>{
                                // console.log('删完了已有的'+filename+ '-----'+ filename +"插入数据库成功"+i);
                            })
                        })
                        let sql = 'insert ignore into homework set username=?,name=?,description=?,filename=?';
                        let data = [username,info.name,info.description,filename];
                        db.base(sql,data,(result)=>{
                            // console.log(filename+ "插入数据库成功"+i);
                        })
 }) 
                   

一开始大概是这样的。查到了,如果查到数量不为0,进行删除。然后插入。但是
在这里插入图片描述
问题来了,先插入再删除。他的执行顺序,调用删除的封装好的操作数据库的函数里的语句是最后执行。

15.textarea的基线对齐

遇到这么个情况,下面的input和前面的文字都是正常。设置相同的样式。而第一个textare文本域发现他前方的文字与文本域不对齐。导致无法居中效果。在这里插入图片描述
而且查看下面input标签与textare标签的距离发现。除了自身的高度和margin,还有一层不知出处的空白区域。而控制台看到的元素盒子也并无此区域。
在这里插入图片描述
再查看正常的input标签。自身的高度和margin上就是上一个input标签而无空白区域。而且已经清除了默认的margin和padding在这里插入图片描述
想到一种可能,和图片容易遇到的问题一样,垂直对齐是基线对齐了。而前方的文字也是因此掉了下去。设置vertical-align:bottom;
解决。

16.twbs-pagination 条件查询的分页问题

主要遇到两个问题。
第一个是由于我是点击后获取到查询的依据类别type。而由于它定义在函数中,是个局部变量。虽然可以成功获取到当前类别的分页总数。但是,点击后,无法分页渲染列表。经过一段段的调试,发现时渲染时的type是undefined。需要定义为全局变量,才可以在加载页面数据的initTypeList(page)中得到type值。

$('#page2').twbsPagination({
        totalPages: Math.ceil(data.result/pageSize),   
        visiblePages: 5,        //可见页码
        first: '首页',
        next: '下一页',
        prev: '上一页',
        last: '尾页',
        onPageClick: function (event, page) {
            initTypeList(page);
        }
});

第二个,当点击后,第一次成功。第二次点击其他条件页面无变化。控制台发现第二次并没有进入到上面的代码段中。其实是涉及到动态设置页数以及页面初始化,分页插件的总页数更改。需要先将原来的destory。才可以实现刷新或重绘。否则加载页面数据onPageClick的函数并没有进入,也就没有initTypeList(page);

可以通过两个简单的步骤来完成。
先调用destroy方法,然后使用新选项对其进行初始化。

$('#page2').twbsPagination('destroy');
$('#page2').twbsPagination({
        totalPages: Math.ceil(data.result/pageSize),   
        visiblePages: 5,        //可见页码
        first: '首页',
        next: '下一页',
        prev: '上一页',
        last: '尾页',
        onPageClick: function (event, page) {
            initTypeList(page);
        }
});

更完整的代码以及说明可以看这篇博文。

17.使用ejs模板渲染题目时,单选按钮出现点击混乱。

原因是遍历的时候,使用的循环遍历。开始没对每个题目进行区分。
他们的name属性和label属性所绑定的id都是一样的。
就会导致判断题,所有的题,只能有一题可以选。而选择题,点击第一题的A选项,可能勾选的是其他的题目,或者点其他的题目选项,把之前的一题答案给更改了。

对于单选radio来说,name的属性值是标榜是否同一个单选项的参考。所以对于一题来说,他们的name 属性必须一致 ,而不同题的name应该不同,此外label标签的for属性绑定的id也是同理。

解决方法,id或者name后增加了遍历的专属题目号<%= data[i].question_id%>

18.ajax往后台传递对象数据的问题

一开始没注意,直接将对象写在了数据头中。

data: {
	'username': username,
	'titleObj': titleObj
}

因为dataType是json。传到后台就会发现,对象被拆开成json数据中去了。然后你不能按你所想的获取。

要注意的是,传递对象数据时,要首先将对象转为json形式字符串,

data: {
	'username': username,
	'titleObj': JSON.stringify(titleObj),
}

然后在后台我们再通过JSON.parse()进行将json形式字符串转为对象的操作。
let titleObj = JSON.parse(req.body.titleObj);

19.批阅试卷时从数据库中获取到的不是按题号顺序的,通过对象数组的每个对象的题号属性进行排序

从数据库获取到考生题目信息是一个对象数组,每一题我都是存在一个对象数组的对象中。这个题目对象有个题号属性,我们可以通过对对象属性进行排序解决由于数据库存储的不按顺序所导致的获取渲染时题目的紊乱。

function compare(property) {
	return function (a, b) {
		return a[property] - b[property];
	}
};
answerData.sort(compare('question_id'));

题目数组调用sort()排序方法,里面传入我们写好的排序规则的函数

20.操作数据库封装的函数改进:将错误交给用户进行流程控制

在之前实现业务逻辑时,封装的操作数据库的函数是出错就抛出

connection.query(sql,data, function(error, results, fields) {
	if (error) throw error;
	callback(results);
});

整体完成逻辑后优化发现并不良好。比如当主键重复插入冲突,抛出了错误,但是我们无法进行控制。
在这里插入图片描述

connection.query(sql,data, function(error, results, fields) {
	if (error) return callback(error);
	callback(results);
});

然后我们在进行调用这个封装好的函数后,就可以错误时进行异常捕获

 db.base(sql,data,(result)=>{
        if(result.errno) {
            console.log(result.errno);
            res.json({
                flag : 2,
                errno : result.errno
            })
        }else if(result.affectedRows == 1){
            res.json({flag : 1});           //反回一个标记 falg=1成功
        }
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值