Hi,大家好,我們昨天完成了表單輸入的機制,但是一個完整的表單輸入功能,不只是將資料存起來而已,在實務上,還需要進行資料的驗證才算是完成整的功能,通常我會認定我的使用者是腦殘 + 眼殘,會儘量以畫面說明 + 資料驗證,儘量避免寫入無效的資料,這就是今天要提的部份,資料驗換機制
資料驗證,顧名思義,就是驗證使用者送出之資料是否符合預期之規則,避免造成無法處理之例狀況,例如該必填的,就需檢查是否為空白、數字內容的,就不可以在裡面放文字、甚至需要限定 0到100 或是數字範圍等等。資料驗證是非常重要的事情,尤其是 node.js 這種弱型別的平台,更是重要,因為型別弄錯造成程式錯誤事小,若是引發未處理的例外狀況造成程式崩潰就是大事了。況且node.js 的執行環境說老實話是很脆弱的,因為 node.js 不是像 PHP、JSP一樣另外掛載在網站伺服器上,程式崩潰時伺服器不會有問題。node.js 若是遇到未處理之例外狀況造成程式崩潰的情況,會連同網站伺服器一起停掉,因此在開發時,務必要針對資料進行慎重處理
PS. 上面說的程式崩潰造成伺服器直接掛掉,有很簡單的解決方法,這個我們會在後續提到*
那麼知道了驗證的重要性,資料驗證項目與驗證時間點為何呢?這個問題大概 10個人會有10答案,我自己的習慣是這樣的
通常可以做為驗證的時間點有下列幾項
1. 前端畫面上以javascript 進行資料驗證,會在表單送出前,或是呼叫資料存檔的 ajax api前進行驗證
2. 後端 router 接收資料時,在 router 驗掉
3. 後端的資料處理模組進行驗證(使用Sequelize 的 validator 機制)
4. 什麼都不做,直接交給資料庫進行驗證
完成的驗證機制是前後端都做,例如我自己通常是1、3一起做,若是真的沒有時間,至少要做第3項,因為在資料進去前還有一道最終防線,而且若是考量到其他特殊需求(例如包含ajax api供其他人呼叫的情況),做在後端會比較理想
純前端的驗證機制其實很多,例如 html5 的 require 設定、自己寫 javascript 的onsubmit 事件進行事前驗證、引用第三方套件的 validation library…等,都是常見的做法。不過今天我們選用的機制,是使用Sequelize的validator,它的最大好處是,可以只寫最低限度的程式,而且因為是在 ORM 的層級中進行檢查,即便上述提到的前端、router 等地方全部漏接了,在進入資料庫前還有一道防線預防不正常的資料進入,以下是範例
'use strict';
const Sequelize = require("sequelize");
const db = require("./database");
const circuit = require("./circuit")
const casefile = require("./casefile")
const object = db.define("cases", {
caseid: {
field: "caseid",
type: Sequelize.STRING(40),
defaultValue: Sequelize.fn('uuid_generate_v4'),
primaryKey: true
},
casedesc: {
field: "casedesc",
type: Sequelize.STRING(20),
validate: {
//驗證資料長度,至少5個字,最多 20個字
len: [5, 20]
}
},
//中間省略
}, {
freezeTableName: true,
timestamps: false
});
object.hasMany(circuit, {
foreignKey: 'mainid',
onDelete: 'CASCADE',
onUpdate: 'CASCADE'
})
object.hasMany(casefile, {
foreignKey: 'mainid',
onDelete: 'CASCADE',
onUpdate: 'CASCADE'
})
module.exports = object;
當我們執行了下列程式碼時
cases.create({casedesc: "aaa", caseinfo: "bbb"})
.then((newdata) => {
resolve(reject)
}).catch((err) => {
reject(err.message)
})
會得到「Validation error: Validation len on casedesc failed」的例外,
這樣子代表我們已經具備了資料驗證的功能了
上述的動作,雖然已經有資料驗證的功能,但是那個訊息不是正常人看得懂的,反而會造成客服人員的問題,因此我們要再進行調整。Sequelize的 validate的機制中,每個檢驗項目都可以改寫成為 js 物件型態,並攜帶 args 和 msg 2個屬性,前者是驗證條件,後者是回傳訊息(部份沒有條件的,例如「isEmail」、isInt」…等,就只有 msg 而已,所以我們可以改成這樣子
//前略
casedesc: {
field: "casedesc",
type: Sequelize.STRING(100),
validate: {
len: {
args: [5, 20],
msg: "標題請輸入 5 字以上,20字以內"
},
}
},
//以下省略
這樣調整完畢後,再執行剛剛的cases.create 時,顯示的訊息為「Validation error: 標題請輸入 5 字以上,20字以內」,至少已經是正常人看得懂的訊息了
據說人要貪心一點XDD,因此我們也可以貪心一點的加入複數的驗證機制,方法如下
//前略
casedesc: {
field: "casedesc",
type: Sequelize.STRING(100),
validate: {
notNull: {
msg: '請務必輸入標題'
}
len: {
args: [5, 20],
msg: "標題請輸入 5 字以上,20字以內"
},
}
},
//以下省略
Sequelize的驗證器有很多種類,也可以例用自訂程式之方式自己寫驗證器,各位可以到這裡 來查看所有的驗證器的項目,在這邊列出我自己常用的
驗證器 | 說明 |
---|---|
isEmail | 驗證為e-mail格式 |
isNumeric、isInt、isDecimal | 驗證為數字 |
notNull | 不得為null |
notEmpty | 不得為空字串 |
isIn | 是否在列舉清單中 |
max | 最大值 |
min | 最小值 |
len | 長度限制,args 若為單一數字,則字串長度 = args,若為[a,b],a<=字串長度<=b |
is | args 為正規表示法,驗證資料是否符合正規表示法 |
自訂 | 驗證是否為台灣日期,格式為3碼年2碼月2碼日 |
從上述例子,我們可以在定義資料表時,同時將資料驗證機制定義完畢,這樣子就完成了最低限度的驗證機制,之後再開發前端頁面和router時,就可以根據不足之處再進行驗證條件的追加。那麼今天完成的部份是驗證器的設定,有了輸入表單,有了驗證器之後。我們還差的就是附件上傳的機制,這部份就留在明天處理吧