上節(jié), 前后端交互功能基本實現(xiàn), 但在實際工程項目中這其實還不夠操禀。
前端捕捉(懟)后端錯誤
就拿項目中目前還存留的bug舉例:
在后端代碼未啟動的情況下二拐,先運行前端服務,會返還如下錯誤
這是因為后端未返回數(shù)據(jù),導致的語法錯誤
因此, 會產生三個問題
1.程序無法運行
2.頁面不美觀
3.不利排查原因
所以這里需要在不影響程序運行的前提下, 將錯誤以彈窗的形式展示出來,
例如:
此處輸入圖片的描述
這樣不管是對開發(fā)人員,還是用戶都更加友好
具體做法:
在ajax里做一層 狀態(tài)碼的判斷
const ajax = function(request) {
var r = new XMLHttpRequest()
r.open(request.method, request.url, true)
if (request.contentType !== undefined) {
r.setRequestHeader('Content-Type', request.contentType)
}
r.onreadystatechange = function(event) {
if(r.readyState === 4) {
+ if(r.status == 200) {
+ const data = JSON.parse(r.response)
+ request.success(data)
+ }
+ if(r.status == 500) {
+ request.error()
+ }
}
}
if (request.method === 'GET') {
r.send()
} else {
r.send(request.data)
}
}
//用Promise封裝原生ajx
const ajaxPromise = function(url, method, form) {
var p = new Promise((resolve, reject) => {
const request = {
url: url,
method: method,
contentType: 'application/json',
success: function(r) {
resolve(r)
},
error: function(e) {
const r = {
success: false,
message: '網絡錯誤, 請重新嘗試',
}
+ resolve(r)
},
}
if (method === 'post') {
const data = JSON.stringify(form)
request.data = data
}
ajax(request)
})
return p
}
然后在前端把message用彈窗顯示出來
//請求列表數(shù)據(jù)
getDataSourseList = async () => {
const { success, message, data } = await AllService.getList()
+ if(success) {
this.setState({
dataSource:data,
})
+ }else {
+ Message.error(`${message}`)
+ }
}
Message為antd的彈窗組件, 如果只是簡單顯示可以用alret()
這里分享一個插曲: antd組件的彈窗組件默認的組件名為小寫 message
而我這里協(xié)議定的字段message同樣是小寫, 所以變量沖突,
這個時候我有兩個選擇
- 要么我認慫,改協(xié)議
- 要么,和惡勢力懟到底
我選擇第二個,改了antd源碼, 將小寫換成了大寫 :) 符合我們這次的主題
當然情況還有很多, 到時根據(jù)狀態(tài)碼設置返回信息即可
后端捕捉(懟)前端錯誤
前端在調試過程中,有可能發(fā)送非法數(shù)據(jù)給后端,
后端在不知情的情況下,操作數(shù)據(jù)庫,很有可能會發(fā)生各種靈異事件
所以后端需要對前端傳遞的參數(shù)進行校正, 并發(fā)出提醒
這樣才能更好的和前端合作(撕逼)
具體做法:
- 引入校正函數(shù)
//tools/commFunc.js
/**
* 校驗 前端請求體
* @param args 前端請求體
* @param field_list 后端modal定義結構體的 keys
* @param require_list 必須字段
* @param is_not_strict 是否嚴格匹配
*/
exports.assemble_args = function (args, field_list, require_list, is_not_strict) {
let kwargs = {};
let key_list = [];
let err_msg = false;
for (let field_name of field_list) {
let has_key = (args[field_name] !== undefined);
if (!is_not_strict) {
has_key = has_key && (args[field_name] !== '');
}
if (has_key) {
let key = field_name;
let value = args[field_name];
if (typeof value === 'string') {
value = value.trim();
} else if (field_name == 'id') {
value = parseInt(value);
}
key_list.push(field_name);
kwargs[key] = value;
}
}
if (require_list && require_list.length) {
let lack_params = [];
for (let k of require_list) {
if (key_list.indexOf(k) == -1) {
lack_params.push(k);
}
}
if (lack_params.length) {
err_msg = `lack params:${lack_params.toString()}`
//throw err_msg;
}
}
return { kwargs, err_msg };
};
exports.goto_err = function (ret, err_msg) {
ret.success = false;
ret.message = err_msg;
ret.code = 400;
return ret;
};
2.檢查請求體中是否有必須字段, 若缺失, 則把缺失信息發(fā)送給前端
//routes/all/js
main.post('/update', async (request, response) => {
let ret = {
"success": true,
"code": 200,
"message": "",
"data": [],
}
const body = request.body,
id = body.id || 0,
status = body.status || 0
- const args = body
if (!id) {
//新建
+ //后端定義的keys
+ const field_list = Object.keys(Model.schema.paths).filter(e=> e!='_id' && e!='id')
+ //檢查請求體中是否有 name, age, address
+ //若缺失,則把缺失信息發(fā)送給前端
+ const { kwargs, err_msg } = commFunc.assemble_args(body, field_list, ['name', 'age', 'address'])
+ if( err_msg ) {
+ let err = commFunc.goto_err(ret, err_msg)
+ response.send(err)
+ return
+ }
const dataSourceObj = await Model.create(kwargs)
ret.data = {
id: dataSourceObj.id, create:true
}
} else if (!status) {
//修改
+ const kwargs = body
const dataSourceObj = await Model.findOne({id: kwargs.id})
+ if(!dataSourceObj) {
+ let err = commFunc.goto_err(ret, `dataSourceInfo id:${kwargs.id} query empty`)
+ response.send(err)
+ return
+ }
for ( let key in kwargs) {
if(key =='_id' || key =='id' ) {
continue
}
dataSourceObj[key]= kwargs[key]
}
const new_dataSourceObj = await dataSourceObj.save()
ret.data = {
id: new_dataSourceObj.id, update:true
}
} else if (status === -1){
//刪除
+ const kwargs = body
const dataSourceObj = await Model.findOne({id: kwargs.id})
+ if(!dataSourceObj) {
+ let err = commFunc.goto_err(ret, `dataSourceInfo id:${kwargs.id} query empty`)
+ response.send(err)
+ return
+ }
const remove = await dataSourceObj.remove()
ret.data = {
id: dataSourceObj.id, delete:true
}
}
response.send(ret)
})
測試失敗示例:
-
創(chuàng)建時缺少參數(shù)
此處輸入圖片的描述 -
修改, 刪除時,id不存在
此處輸入圖片的描述
(完...)