提交数据库请求1次插入库2条记录的问题

312 阅读6分钟

写个人博客的时候,提交博客内容到数据库的时候,后台报错Cannot render headers after they are sent to the client,搜索发现,是连续发送了2条入库请求导致的,到数据库查看发现插入了2条新数据

猜测可能是传入的数据太大,被截断了分成了2条插入数据库的

Error [ERR_HTTP_HEADERS_SENT]: Cannot render headers after they are sent to the client
    at ServerResponse.writeHead (_http_server.js:236:13)
    at D:\xhn\programs\deltaning.com\web\BlogController.js:139:17
    at Query.<anonymous> (D:\xhn\programs\deltaning.com\dao\BlogDao.js:23:13)
    at Query.<anonymous> (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\Connection.js:526:10)
    at Query._callback (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\Connection.js:488:16)
    at Query.Sequence.end (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
    at Query._handleFinalResultPacket (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\protocol\sequences\Query.js:149:8)
    at Query.OkPacket (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\protocol\sequences\Query.js:74:10)
    at Protocol._parsePacket (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\protocol\Protocol.js:291:23)
    at Parser._parsePacket (D:\xhn\programs\deltaning.com\node_modules\mysql\lib\protocol\Parser.js:433:10)


1、检查插入库的方法

在插入库的方法中,打印传入的数据,发现打印了2次,就是一条数据被截断成两条分别被打印出来的,打印结果如下

insert blog.................
77777777777777 { content:
   '<p>之前公司有https的需求,就在服务器上用nginx配置ssl证书。</p><p><br></p><p>今天突然有用户说安卓手机提示网站证书有问题</p><p class="">我在pc端浏览器和ios手机上访问都没有出现这个问题,有个别安卓机出现了这个问题,就找了个一个<a href="https://www.geocerts.com/ssl-checker" target="_blank" rel="nofollow noopener noreferrer">网站</a>检查一下网站的ssl证书,发现确实存在问题</p><p class="">如下图所示,说是证书链不完整</p><p class=""><br></p><p><img src="data:image/jpeg;base64,iVBORw0KG
  views: 0,
  tags: 'yujj',
  ctime: 1585798851,
  utime: 1585798851 }
insert blog.................
77777777777777 { content:
   'CiCFDIiiEEEIIICYII="><br></p><p><br></p><p>其实问题就是crt文件中缺少中间证书,使用<a href="https://myssl.com/chain_download.html" target="_blank" rel="nofollow noopener noreferrer">myssl.com/chain_downl…</a>可以生成中间证书,生产中间证书之后,把中间证书的内容完完全全的复制并追加到crt/cer文件后面(不要有空格,空行)就可以了</p><div><br></div>',
  title: '888888888888888888',
  views: 0,
  tags: 'yujj',
  ctime: 1585798851,
  utime: 1585798851 }

如上面的代码所示,content字段被分成了2段打印出来的

2、检查调用插入库方法的接口

app.post('/editBlog', function editBlog(req, res) {
    // 获取url中的参数
    var params = url.parse(req.url, true).query;
    var tags = params.tags.replace(/ /g, "").replace(/,/g, ',');
    req.on('data', function (data) {
        // 将数据插入到数据库
        console.log('6666666666666666666666',data.toString());
        blogDao.insertBlog(data.toString(), params.title, tags, 0, timeUtil.getNowDate(), timeUtil.getNowDate(), function (result) {
            res.writeHead(200);
            res.write(respUtil.writeResult('success', '操作成功', null));
            res.end();
        })
    })
})

打印结果

6666666666666666666666 <p>之前公司有https的需求,就在服务器上用nginx配置ssl证书。</p><p><br></p><p>今天突然有用户说安卓手机提示网站证书有问题</p><p class="">我在pc端浏览器和ios手机上访问都没有出现这个问题,有个别安卓机出现了这个问题,就找了个一个<a href="https://www.geocerts.com/ssl-checker" target="_blank" rel="nofollow noopener noreferrer">网站</a>检查一下网站的ssl证书,发现确实存在问题</p><p class="">如下图所示,说是证书链不完整</p><p class=""><br></p><p><img src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAzEAAAEQCAYAAACA+fo6AAAAAX

...

6666666666666666666666 EEENFUfw/kznzSCFaxZMAAAAASUVORK5CYII="><br></p><p><br></p><p>其实问题就是crt文件中缺少中间证书,使用<a href="https://myssl.com/chain_download.html" target="_blank" rel="nofollow noopener noreferrer">myssl.com/chain_downl…</a>可以生成中间证书,生产中间证书之后,把中间证书的内容完完全全的复制并追加到crt/cer文件后面(不要有空格,空行)就可以了</p><div><br></div>


果然,打印出了2段被分裂的内容

就说明其实是接口调用了2次入库的方法,到底是什么原因在往上查

3、检查前端调用接口传入的数据

发现只调用了1次接口,传输的数据也是完整的

由此发现,是接口层接收数据出了问题

就猜想是不是req.on('data', function() {})监听data事件对数据有接收限制,就改成了使用body-parser去接收数据

Request Payload方式是以“流“”的方式出入到后台,需要监听data事件来获取完整的数据。

app.post('/editBlog', function editBlog(req, res) {
    // 获取url中的参数
    var params = url.parse(req.url, true).query;
    var tags = params.tags.replace(/ /g, "").replace(/,/g, ',');
    // 监听client端发送的请求数据
    console.log(req.body.content)
    if (!req.body) {
        return res.sendStatus(400)
    }
    var content = req.body.content;
    blogDao.insertBlog(content, params.title, tags, 0, timeUtil.getNowDate(), timeUtil.getNowDate(), function (result) {
        // console.log('controller 22222222222222222222222', content);
        res.writeHead(200);
        res.write(respUtil.writeResult('success', '操作成功', null));
        res.end();
    });
})


使用了body-parser之后,发现报错Error: request entity too large

传入的参数太大了,body-parser默认的负载限制是100kb,修改负载限制为50mb

app.use(bodyParser.urlencoded({limit: '50mb', extende:true}));

app.use(bodyParser.json({limit: '50mb'}));

不报错了,后台打印的数据也是完成的一条数据,去查看数据发现只插入了1条,以为没问题了,点击content字段发现,插入的内容不完整,oh my god~ 这是怎么回事呢,content字段的类型已经设置为了text,难道text还是不够,把text类型改成了longtext,然后发现,ok了,没有报错,数据库插入了1条数据,数据是完整的

完美解决

附赠一下mysql字符串类型的长度


问题解决之后,我又把body-parser改回了req.on('data', function() {})尝试了一下,还是插入了2条数据到数据库,数据是被截断的,就确认是监听data事件的问题,data事件把收到的请求数据分成了2条分别插入数据库的,也返回了2条响应数据给浏览器,浏览器接收到1条之后,接口通道就关闭了,所以后台发送第2条数据的时候就报错了