咨詢服務(wù)熱線:400-099-8848
你寫的每一個(gè)爛表單,都是由于校驗(yàn)次序搞反了 |
| 發(fā)布時(shí)間:2026-05-09 文章來源:網(wǎng)絡(luò) 瀏覽次數(shù):110 |
表單校驗(yàn)的規(guī)劃邏輯遠(yuǎn)比想象中更值得沉思。從空值攔截到數(shù)據(jù)庫查重,五層校驗(yàn)架構(gòu)揭示了數(shù)據(jù)過濾的黃金法則——本錢越低的檢查越應(yīng)前置。本文將拆解這套源于數(shù)據(jù)庫優(yōu)化思維的校驗(yàn)范式,揭示前端與后端校驗(yàn)的協(xié)同策略,以及如何用一張矩陣表徹底解決開發(fā)與測驗(yàn)的交流難題。 上星期review代碼,后端搭檔寫了個(gè)新增數(shù)據(jù)的接口。我點(diǎn)開一看,校驗(yàn)邏輯大概是這么個(gè)畫風(fēng): 先查數(shù)據(jù)庫看有沒有重復(fù)記錄,再校驗(yàn)字段格局,最終才判別必填項(xiàng)有沒有傳。 我說兄弟,用戶連產(chǎn)品名都沒填呢,你就去查庫了?數(shù)據(jù)庫它也是有愛情的好吧。 他愣了一下:”這有啥區(qū)別嗎?橫豎最終都會(huì)報(bào)錯(cuò)! 區(qū)別大了。校驗(yàn)?zāi)懿荒軘r住臟數(shù)據(jù)是及格線,校驗(yàn)的次序才是你規(guī)劃水平的分界線。 這事讓我想起之前踩過的一個(gè)坑。 咱們體系有個(gè)”新增周度數(shù)據(jù)”的表單——產(chǎn)品、企業(yè)、省份、周產(chǎn)值、周庫存、價(jià)格、本錢、毛利,十幾個(gè)字段。剛上線那會(huì)兒,校驗(yàn)邏輯是前端搭檔”憑感覺”寫的,想到哪驗(yàn)到哪。 成果呢,用戶填了個(gè)負(fù)數(shù)的價(jià)格,體系沒攔住,直接跑去做毛利核算了。算出來一個(gè)離譜的毛利率,存進(jìn)了數(shù)據(jù)庫。下游的價(jià)格剖析模塊一讀這條數(shù)據(jù)——Loss預(yù)測直接飛了,剖析師第二天跑來問咱們”這個(gè)品種是不是出bug了”。 查了半天,便是由于規(guī)模校驗(yàn)被放在了相關(guān)核算的后邊。價(jià)格是負(fù)數(shù)這件事,本來在第三層就該攔住的,成果漏到了第四層,還引發(fā)了連鎖反應(yīng)。 一個(gè)校驗(yàn)放錯(cuò)方位,鏈路上一切下游都跟著遭殃。 這事之后我就開端揣摩:表單校驗(yàn)這東西,究竟有沒有一套通用的、穩(wěn)定的規(guī)劃范式? 還真有。并且特別樸素。 五層過濾,越廉價(jià)的檢查越先跑我后來把校驗(yàn)邏輯梳理成了五層。不是我發(fā)明的,你去看任何一個(gè)老練結(jié)構(gòu)的參數(shù)校驗(yàn),底層邏輯都是這個(gè): L1 — 存在性:傳沒傳? 最廉價(jià)的檢查。字段是不是null、空字符串、undefined。帶星號的必填項(xiàng),這一層全覆蓋。用戶點(diǎn)提交,先掃一遍,沒填的直接標(biāo)紅,后邊悉數(shù)越過。 為什么放第一層?由于一個(gè)空值,你去做格局校驗(yàn)沒含義,做規(guī)模校驗(yàn)更沒含義。就好比你拿到一個(gè)null去調(diào).length,不是校驗(yàn)失利的問題,是直接NPE給你看。 L2 — 格局類型:像不像? 字段有值了,看看這個(gè)值的”形狀”對不對。周產(chǎn)值填了”哈哈哈”——類型不對。日期字段收到一個(gè)”2026-13-45″——格局不合法。郵箱沒有@符號。手機(jī)號混進(jìn)了字母。 這一層實(shí)質(zhì)上是做類型轉(zhuǎn)化前的門衛(wèi)。過了這關(guān),后邊的邏輯才干拿到一個(gè)”至少類型是對的”的值去做進(jìn)一步判別。 許多前端結(jié)構(gòu)(Ant Design的Form、Element的el-form)自帶的validator其實(shí)就管到這一層。但光靠這層遠(yuǎn)遠(yuǎn)不夠。 L3 — 規(guī)模邊界:合不合理? 格局對了不代表值是合理的。價(jià)格不能為負(fù)數(shù)。庫存不能是-500萬噸。年度不能填2099年。百分比字段不能呈現(xiàn)200%。 這一層過濾的是”格局正確但事務(wù)上離譜”的數(shù)據(jù)。我管這叫”合法的垃圾”——類型體系認(rèn)它,事務(wù)邏輯不認(rèn)它。 經(jīng)常被忽略的一個(gè)細(xì)節(jié):小數(shù)精度也屬于這一層。價(jià)格保存兩位小數(shù),你傳進(jìn)來一個(gè)3.14159,后邊核算會(huì)不會(huì)出精度漂移?該在這里就truncate或許round掉。 L4 — 相關(guān)邏輯:字段之間自洽嗎? 單字段都合法了,但字段之間可能打架。 毛利 = (價(jià)格 – 本錢) / 價(jià)格。這三個(gè)字段之間有硬束縛。用戶手動(dòng)填了毛利和價(jià)格,但填的本錢算出來對不上——這便是跨字段邏輯校驗(yàn)該干的活。 還有一類更蔭蔽的:條件必填。比如選了某個(gè)產(chǎn)品工藝之后,產(chǎn)值單位的可選規(guī)模要聯(lián)動(dòng)變化。選了”省份”之后,”企業(yè)”的下拉列表要跟著過濾。 這一層的本錢比前三層高不少,由于你要同時(shí)拿到多個(gè)字段的值做交叉判別。所以它排在第四。 L5 — 大局外部:跟體系里已有的數(shù)據(jù)抵觸嗎? 最貴的一層。要查庫。 同一個(gè)”產(chǎn)品 + 企業(yè) + 省份 + 周度時(shí)間”的組合,不能重復(fù)錄入。這個(gè)判別必須發(fā)懇求到后端,后端去數(shù)據(jù)庫里跑一條select。網(wǎng)絡(luò)IO + 數(shù)據(jù)庫查詢,這是整個(gè)校驗(yàn)鏈路里本錢最高的操作。 所以放在最終。只有前面四層悉數(shù)pass了,才值得發(fā)這一趟懇求。 你想想,假如把L5放在L1前面會(huì)怎樣?用戶連必填項(xiàng)都沒填全,你就發(fā)了一次數(shù)據(jù)庫查詢。并發(fā)高一點(diǎn),這種無效查詢能把你的DB連接池吃得干干凈凈。 實(shí)質(zhì)便是個(gè)短路求值。任何一層掛了,后邊不跑。這不是什么高深的規(guī)劃模式,便是最樸素的本錢排序——選擇性高、代價(jià)低的條件先履行。 你去看數(shù)據(jù)庫查詢優(yōu)化器選履行計(jì)劃的邏輯,一模相同的思路。MySQL決定先走哪個(gè)索引、先過濾哪個(gè)條件,背后也是這套”廉價(jià)的先來”。 這套思路不只管表單你再想遠(yuǎn)一點(diǎn)。 API接口參數(shù)校驗(yàn),是不是同一套?收到懇求 → 必傳參數(shù)在不在 → 類型對不對 → 值域合不合理 → 參數(shù)間邏輯(start_date < end_date)→ 權(quán)限校驗(yàn)(查Redis/查DB)。任何一個(gè)老練的API結(jié)構(gòu),中間件鏈的排列次序便是按這個(gè)來的。 ETL數(shù)據(jù)清洗,也是。拿到一批CSV → 空行刪掉 → 格局一致(日期轉(zhuǎn)ISO、數(shù)字去逗號)→ 異常值過濾(價(jià)格為負(fù)的行剔除)→ 跨字段一致性校驗(yàn) → 跟主表去重。你要是把去重放在第一步,幾百萬條數(shù)據(jù)先全量join一遍,跑到天荒地老。 甚至代碼review的時(shí)分,你看一個(gè)PR,下意識(shí)的掃描次序也是:這個(gè)改動(dòng)有沒有(L1,別是個(gè)空PR)→ 改的對不對地方(L2,文件和模塊對不對)→ 改動(dòng)幅度合不合理(L3,是不是改了不應(yīng)改的)→ 跟其他模塊有沒有抵觸(L4)→ CI跑過沒有(L5,外部驗(yàn)證)。 同一套模型,不同的皮膚。 落地的時(shí)分,一張表搞定回到實(shí)際工作。我現(xiàn)在寫PRD里的表單需求,直接用一張校驗(yàn)規(guī)矩矩陣表跟開發(fā)對齊: 比在PRD里寫一大段”當(dāng)用戶輸入價(jià)格時(shí),體系應(yīng)判別價(jià)格是否為空,假如為空則提示……假如不為空則持續(xù)判別格局……”清楚十倍。開發(fā)拿到這張表,每個(gè)字段每一層該干嘛,一望而知,不用反復(fù)對齊。 測驗(yàn)搭檔也愛這張表。寫測驗(yàn)用例的時(shí)分,每一層便是一組case。L1的case:每個(gè)必填字段分別傳空。L2的case:每個(gè)字段分別傳不合法格局。這么列下來,漏測的概率小許多。 前端校驗(yàn)和后端校驗(yàn)的聯(lián)系順便說一個(gè)容易吵架的點(diǎn)。 前端該不應(yīng)做校驗(yàn)?當(dāng)然該做。用戶體會(huì)好,即時(shí)反應(yīng),不用等網(wǎng)絡(luò)往復(fù)。 但前端校驗(yàn)?zāi)懿荒墚?dāng)安全防地?不能。由于前端校驗(yàn)可以被繞過——隨意開個(gè)Postman直接打接口,你的前端校驗(yàn)跟沒有相同。 所以正確的做法是:前端做L1到L4,體會(huì)層面攔一道。后端L1到L5悉數(shù)重跑一遍,這是安全兜底。L5本來就要查庫,只能在后端做。 別覺得后端重復(fù)跑一遍是浪費(fèi)。安全領(lǐng)域有個(gè)原則叫”縱深防護(hù)”——不是一道墻夠高就行,是多道墻疊在一同,每道都有可能攔住一類攻擊。校驗(yàn)也是相同。 有些團(tuán)隊(duì)為了省勁,前端做了校驗(yàn)后端就不做了。我只能說,等哪天被人用腳本往你接口里灌臟數(shù)據(jù)的時(shí)分,你就知道這個(gè)偷閑有多貴了。 說究竟,校驗(yàn)規(guī)劃這件事沒有什么花活。就一條原則: 先做廉價(jià)的判別,再做貴的判別。先用本地信息,再用外部信息。先查格局,再查語義。 把這條刻進(jìn)DNA里,不管是寫表單、規(guī)劃API、搭數(shù)據(jù)管道仍是做音訊消費(fèi),你的校驗(yàn)邏輯都不會(huì)太離譜。 至于那個(gè)把查庫放在第一步的搭檔——他后來重構(gòu)了。現(xiàn)在那段代碼的注釋寫著: “L1→L5,別改次序。改了請客。” |
|