gpt4 book ai didi

Node.js MySQL 错误处理

转载 作者:IT老高 更新时间:2023-10-28 23:08:07 26 4
gpt4 key购买 nike

我已经阅读了几个在 node.js 中使用 mysql 的示例,但我对错误处理有疑问。

大多数示例都是这样处理错误的(可能是为了简洁):

app.get('/countries', function(req, res) {

pool.createConnection(function(err, connection) {
if (err) { throw err; }

connection.query(sql, function(err, results) {
if (err) { throw err; }

connection.release();

// do something with results
});
});
});

这会导致服务器在每次出现 sql 错误时崩溃。我想避免这种情况并保持服务器运行。

我的代码是这样的:

app.get('/countries', function(req, res) {

pool.createConnection(function(err, connection) {
if (err) {
console.log(err);
res.send({ success: false, message: 'database error', error: err });
return;
}

connection.on('error', function(err) {
console.log(err);
res.send({ success: false, message: 'database error', error: err });
return;
});

connection.query(sql, function(err, results) {
if (err) {
console.log(err);
res.send({ success: false, message: 'query error', error: err });
return;
}

connection.release();

// do something with results
});
});
});

我不确定这是否是处理它的最佳方式。我还想知道查询的 err block 中是否应该有一个 connection.release() 。否则,连接可能会保持打开状态并随着时间的推移而建立。

我已经习惯了 Java 的 try...catch...finallytry-with-resources 在这里我可以“干净地”捕获任何错误并关闭所有我的资源在最后。有没有办法向上传播错误并在一个地方处理它们?

最佳答案

我决定使用 es2017 语法和 Babel 来处理它以转换为 Node 7 支持的 es2016。

较新版本的 Node.js 无需转译即可支持此语法。

这是一个例子:

'use strict';

const express = require('express');
const router = express.Router();

const Promise = require('bluebird');
const HttpStatus = require('http-status-codes');
const fs = Promise.promisifyAll(require('fs'));

const pool = require('./pool'); // my database pool module, using promise-mysql
const Errors = require('./errors'); // my collection of custom exceptions


////////////////////////////////////////////////////////////////////////////////
// GET /v1/provinces/:id
////////////////////////////////////////////////////////////////////////////////
router.get('/provinces/:id', async (req, res) => {

try {

// get a connection from the pool
const connection = await pool.createConnection();

try {

// retrieve the list of provinces from the database
const sql_p = `SELECT p.id, p.code, p.name, p.country_id
FROM provinces p
WHERE p.id = ?
LIMIT 1`;
const provinces = await connection.query(sql_p);
if (!provinces.length)
throw new Errors.NotFound('province not found');

const province = provinces[0];

// retrieve the associated country from the database
const sql_c = `SELECT c.code, c.name
FROM countries c
WHERE c.id = ?
LIMIT 1`;
const countries = await connection.query(sql_c, province.country_id);
if (!countries.length)
throw new Errors.InternalServerError('country not found');

province.country = countries[0];

return res.send({ province });

} finally {
pool.releaseConnection(connection);
}

} catch (err) {
if (err instanceof Errors.NotFound)
return res.status(HttpStatus.NOT_FOUND).send({ message: err.message }); // 404
console.log(err);
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message }); // 500
}
});


////////////////////////////////////////////////////////////////////////////////
// GET /v1/provinces
////////////////////////////////////////////////////////////////////////////////
router.get('/provinces', async (req, res) => {

try {

// get a connection from the pool
const connection = await pool.createConnection();

try {

// retrieve the list of provinces from the database
const sql_p = `SELECT p.id, p.code, p.name, p.country_id
FROM provinces p`;
const provinces = await connection.query(sql_p);

const sql_c = `SELECT c.code, c.name
FROM countries c
WHERE c.id = ?
LIMIT 1`;

const promises = provinces.map(async p => {

// retrieve the associated country from the database
const countries = await connection.query(sql_c, p.country_id);

if (!countries.length)
throw new Errors.InternalServerError('country not found');

p.country = countries[0];

});

await Promise.all(promises);

return res.send({ total: provinces.length, provinces });

} finally {
pool.releaseConnection(connection);
}

} catch (err) {
console.log(err);
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message }); // 500
}
});


////////////////////////////////////////////////////////////////////////////////
// OPTIONS /v1/provinces
////////////////////////////////////////////////////////////////////////////////
router.options('/provinces', async (req, res) => {
try {
const data = await fs.readFileAsync('./options/provinces.json');
res.setHeader('Access-Control-Allow-Methods', 'HEAD,GET,OPTIONS');
res.setHeader('Allow', 'HEAD,GET,OPTIONS');
res.send(JSON.parse(data));
} catch (err) {
res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message });
}
});


module.exports = router;

使用 async/await 和这个 try { try { } finally { } } catch { } 模式 可以进行干净的错误处理,您可以在一个地方收集和处理所有错误。 finally block 无论如何都会关闭数据库连接。

您只需要确保自始至终都在处理 promise 。对于数据库访问,我使用 promise-mysql 模块而不是普通的 mysql 模块。对于其他一切,我使用 bluebird 模块和 promisifyAll()

我也有自定义的异常类,我可以在某些情况下抛出它们,然后在 catch block 中检测它们。根据 try block 中可能引发的异常,我的 catch block 可能如下所示:

catch (err) {
if (err instanceof Errors.BadRequest)
return res.status(HttpStatus.BAD_REQUEST).send({ message: err.message }); // 400
if (err instanceof Errors.Forbidden)
return res.status(HttpStatus.FORBIDDEN).send({ message: err.message }); // 403
if (err instanceof Errors.NotFound)
return res.status(HttpStatus.NOT_FOUND).send({ message: err.message }); // 404
if (err instanceof Errors.UnprocessableEntity)
return res.status(HttpStatus.UNPROCESSABLE_ENTITY).send({ message: err.message }); // 422
console.log(err);
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ error: err, message: err.message });
}

pool.js:

'use strict';

const mysql = require('promise-mysql');

const pool = mysql.createPool({
connectionLimit: 100,
host: 'localhost',
user: 'user',
password: 'password',
database: 'database',
charset: 'utf8mb4',
debug: false
});


module.exports = pool;

errors.js:

'use strict';

class ExtendableError extends Error {
constructor(message) {
if (new.target === ExtendableError)
throw new TypeError('Abstract class "ExtendableError" cannot be instantiated directly.');
super(message);
this.name = this.constructor.name;
this.message = message;
Error.captureStackTrace(this, this.contructor);
}
}

// 400 Bad Request
class BadRequest extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('bad request');
else
super(m);
}
}

// 401 Unauthorized
class Unauthorized extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('unauthorized');
else
super(m);
}
}

// 403 Forbidden
class Forbidden extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('forbidden');
else
super(m);
}
}

// 404 Not Found
class NotFound extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('not found');
else
super(m);
}
}

// 409 Conflict
class Conflict extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('conflict');
else
super(m);
}
}

// 422 Unprocessable Entity
class UnprocessableEntity extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('unprocessable entity');
else
super(m);
}
}

// 500 Internal Server Error
class InternalServerError extends ExtendableError {
constructor(m) {
if (arguments.length === 0)
super('internal server error');
else
super(m);
}
}


module.exports.BadRequest = BadRequest;
module.exports.Unauthorized = Unauthorized;
module.exports.Forbidden = Forbidden;
module.exports.NotFound = NotFound;
module.exports.Conflict = Conflict;
module.exports.UnprocessableEntity = UnprocessableEntity;
module.exports.InternalServerError = InternalServerError;

关于Node.js MySQL 错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40141332/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com