iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0

Hi,大家好,我們昨天完成了表單輸入的機制,但是一個完整的表單輸入功能,不只是將資料存起來而已,在實務上,還需要進行資料的驗證才算是完成整的功能,通常我會認定我的使用者是腦殘 + 眼殘,會儘量以畫面說明 + 資料驗證,儘量避免寫入無效的資料,這就是今天要提的部份,資料驗換機制

什麼是資料驗證,該在什麼時候做呢?

資料驗證,顧名思義,就是驗證使用者送出之資料是否符合預期之規則,避免造成無法處理之例狀況,例如該必填的,就需檢查是否為空白、數字內容的,就不可以在裡面放文字、甚至需要限定 0到100 或是數字範圍等等。資料驗證是非常重要的事情,尤其是 node.js 這種弱型別的平台,更是重要,因為型別弄錯造成程式錯誤事小,若是引發未處理的例外狀況造成程式崩潰就是大事了。況且node.js 的執行環境說老實話是很脆弱的,因為 node.js 不是像 PHP、JSP一樣另外掛載在網站伺服器上,程式崩潰時伺服器不會有問題。node.js 若是遇到未處理之例外狀況造成程式崩潰的情況,會連同網站伺服器一起停掉,因此在開發時,務必要針對資料進行慎重處理
PS. 上面說的程式崩潰造成伺服器直接掛掉,有很簡單的解決方法,這個我們會在後續提到*

那麼知道了驗證的重要性,資料驗證項目與驗證時間點為何呢?這個問題大概 10個人會有10答案,我自己的習慣是這樣的

  1. 資料庫的必填欄位一定要進行驗證,至少要設定不得為空值
  2. 數字欄位的話,至少要驗證為數字型態。部份有明確範圍的(例如百分比的,會進行範圍限定0~100)
  3. 明確格式的資料,例如 e-mail、信用卡號…等會進行驗證(利用 re來處理)
  4. 日期格式資料會驗證是否為日期(不過通常會直接在前端上限定以日期選單輸入,不會讓使用者自己手打)
  5. 資料庫中有不得重複的項目時,在寫入資料前進行驗證(這個只會在後端做)

通常可以做為驗證的時間點有下列幾項
1. 前端畫面上以javascript 進行資料驗證,會在表單送出前,或是呼叫資料存檔的 ajax api前進行驗證
2. 後端 router 接收資料時,在 router 驗掉
3. 後端的資料處理模組進行驗證(使用Sequelize 的 validator 機制)
4. 什麼都不做,直接交給資料庫進行驗證
完成的驗證機制是前後端都做,例如我自己通常是1、3一起做,若是真的沒有時間,至少要做第3項,因為在資料進去前還有一道最終防線,而且若是考量到其他特殊需求(例如包含ajax api供其他人呼叫的情況),做在後端會比較理想

使用Sequelize 的 validator

第一步

純前端的驗證機制其實很多,例如 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時,就可以根據不足之處再進行驗證條件的追加。那麼今天完成的部份是驗證器的設定,有了輸入表單,有了驗證器之後。我們還差的就是附件上傳的機制,這部份就留在明天處理吧


上一篇
客服問題表單輸入功能
下一篇
加入檔案上傳功能
系列文
以vue.js + node.js 搭建一個客服填單系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言