背景
以前在寫 SpringBoot
全棧開發(fā)的系列文章中全棧開發(fā)之后端腳手架:SpringBoot集成MybatisPlus代碼生成,分頁(yè),雪花算法,統(tǒng)一響應(yīng),異常攔截,Swagger3接口文檔,有提到對(duì)后端接口的響應(yīng)數(shù)據(jù)進(jìn)行統(tǒng)一的封裝,方便前端或者第三方進(jìn)行數(shù)據(jù)獲取與對(duì)接工作;統(tǒng)一響應(yīng)一般包含狀態(tài)碼、消息內(nèi)容、數(shù)據(jù)內(nèi)容等。
這里對(duì) 2017
年寫的一個(gè)基于 Node.js
的 Express.js
框架開發(fā)的后端項(xiàng)目的接口進(jìn)行類似的封裝。
通用狀態(tài)碼與信息封裝
/**
* @author ycx
* @description 業(yè)務(wù)異常通用code
*
*/
class BaseResultCode {
/***********************************/
/**
* code
*/
code;
/**
* 說(shuō)明
*/
desc;
constructor(code, desc) {
this.code = code;
this.desc = desc;
}
/************************************/
static SUCCESS = new BaseResultCode(200, '成功');
static FAILED = new BaseResultCode(500, '失敗');
static VALIDATE_FAILED = new BaseResultCode(400, '參數(shù)校驗(yàn)失敗');
static API_NOT_FOUNT = new BaseResultCode(404, '接口不存在');
static API_BUSY = new BaseResultCode(429, '操作過(guò)于頻繁')
}
module.exports = BaseResultCode
Note: 上面的 class
寫法對(duì) Node.js
的版本有要求, 10.x
報(bào)錯(cuò), 12.x
可以使用。
統(tǒng)一響應(yīng)封裝
const ResultCode = require('./BaseResultCode');
/**
* @author ycx
* @description 統(tǒng)一返回結(jié)果
*/
class Result {
/**
* 返回code
*/
code;
/**
* 返回消息
*/
msg;
/**
* 返回?cái)?shù)據(jù)
*/
data;
/**
* 返回時(shí)間
*/
time;
/**
*
* @param code {number} 返回code
* @param msg {string} 返回消息
* @param data {any} 返回具體對(duì)象
*/
constructor(code, msg, data) {
this.code = code;
this.msg = msg;
this.data = data;
this.time = Date.now();
}
/**
* 成功
* @param data {any} 返回對(duì)象
* @return {Result}
*/
static success(data) {
return new Result(ResultCode.SUCCESS.code, ResultCode.SUCCESS.desc, data);
}
/**
* 失敗
*/
static fail(errData) {
return new Result(ResultCode.FAILED.code, ResultCode.FAILED.desc, errData);
}
/**
* 參數(shù)校驗(yàn)失敗
*/
static validateFailed(param) {
return new Result(ResultCode.VALIDATE_FAILED.code, ResultCode.VALIDATE_FAILED.desc, param);
}
/**
* 攔截到的業(yè)務(wù)異常
* @param bizException {BizException} 業(yè)務(wù)異常
*/
static bizFail(bizException) {
return new Result(bizException.code, bizException.msg, null);
}
}
module.exports = Result
返回?cái)?shù)據(jù)時(shí)進(jìn)行封裝
封裝好統(tǒng)一的響應(yīng)后,在 Express.js
后端項(xiàng)目中怎么使用?先是引入: const Result = require("../common/Result");
,然后直接使用 Result.success()
或者 Result.fail()
返回?cái)?shù)據(jù)或錯(cuò)誤信息。
const router = express.Router();
const Result = require("../common/Result");
router.get("/:productName/:deviceName", function(req, res) {
let productName = req.params.productName;
let deviceName = req.params.deviceName;
Device.findOne({
"product_name": productName,
"device_name": deviceName
}, function(err, device) {
if (err) {
res.send(Result.fail(err));
} else {
if (device != null) {
Connection.find({
device: device._id
}, function(_, connections) {
res.json(Result.success(Object.assign(device.toJSONObject(), {
connections: connections.map(function(conn) {
return conn.toJSONObject();
})
})))
})
} else {
res.status(404).json({
error: "Not Found"
});
}
}
})
});
router.put("/:productName/:deviceName/suspend", function(req, res) {
let productName = req.params.productName
let deviceName = req.params.deviceName
Device.findOneAndUpdate({
"product_name": productName,
"device_name": deviceName
}, {
status: "suspended"
}, {
useFindAndModify: false
}).exec(function(err, device) {
if (err) {
res.send(Result.fail(err));
} else {
if (device != null) {
device.disconnect();
}
res.status(200).send(Result.success("ok"));
}
})
});
Note:順便在這里簡(jiǎn)單總結(jié)下 Express.js
獲取請(qǐng)求參數(shù)的幾種方法:
- req.query.productName,對(duì)應(yīng)http://localhost:3000/device?productName=product
- req.params.productName,對(duì)應(yīng)http://localhost:3000/device/:productName
- req.headers[“productname”],獲取頭信息中的參數(shù),注意小寫~
- req.body.productName,Express.js無(wú)法直接獲取Post請(qǐng)求的參數(shù),需要設(shè)置body解析中間件,app.use(express.urlencoded())
可能遇到的問題
Express 請(qǐng)求沒有響應(yīng) 日志顯示:-- ms
原因:在響應(yīng)時(shí)沒有調(diào)用 res.send()
或者 next()
向下執(zhí)行,導(dǎo)致最終沒有結(jié)果返回給調(diào)用方。
router.put("/:productName/:deviceName/suspend", function(req, res) {
let productName = req.params.productName
let deviceName = req.params.deviceName
Device.findOneAndUpdate({
"product_name": productName,
"device_name": deviceName
}, {
status: "suspended"
}, {
useFindAndModify: false
}).exec(function(err, device) {
if (err) {
res.send(err));
} else {
if (device != null) {
device.disconnect();
}
Result.success("ok");
}
})
});
解決方法: 將 Result.success
放到 res.send()
里,就像這樣: res.send(Result.success("ok"))
。
結(jié)果展示
小總結(jié)
上述內(nèi)容記錄了對(duì) Node.js
后端框架 Express.js
(如果使用的是 Koa.js
,方法也類似)的接口進(jìn)行統(tǒng)一響應(yīng)封裝的方法以及可能遇到的問題,后端開發(fā)時(shí),對(duì)響應(yīng)和異常進(jìn)行統(tǒng)一封裝有幾個(gè)好處:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-754240.html
- 統(tǒng)一風(fēng)格:通過(guò)封裝,可以確保所有的響應(yīng)和異常都遵循相同的格式和風(fēng)格,使代碼更加一致和易于理解。
- 便于維護(hù):統(tǒng)一封裝可以讓你更容易地管理和維護(hù)響應(yīng)和異常的邏輯,而不必在每個(gè)地方都重復(fù)相同的代碼。
- 安全性:通過(guò)封裝異常,可以更好地處理錯(cuò)誤情況,確保系統(tǒng)的安全性和穩(wěn)定性。
- 易于擴(kuò)展:封裝可以讓你更容易地?cái)U(kuò)展和修改響應(yīng)和異常的處理邏輯,而不必改動(dòng)大量的代碼。
總之,統(tǒng)一封裝可以提高代碼的可維護(hù)性、安全性和可擴(kuò)展性,這是在進(jìn)行 HTTP
接口開發(fā)時(shí)的一個(gè)最佳實(shí)踐。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-754240.html
Reference
- code筆記:nodeJS框架 express 接口統(tǒng)一返回結(jié)果設(shè)計(jì)
到了這里,關(guān)于Node后端框架Express與Koa接口統(tǒng)一響應(yīng)封裝的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!