fix(app): 字數上限與後端數的不是同一種單位——計數器說沒超過,後端擋下(第二十六輪) - #98
Merged
Conversation
本輪掃的族是跨端輸入邊界對帳(App 欄位上限 vs 後端 validator),從沒掃過。 掃出來的東西比預期硬:不只有三個欄位沒擋,**有擋的那三個擋的單位也是錯的**。 根因:Flutter 的 TextField.maxLength 數的是 grapheme cluster,後端每一支上限數的 都是 rune。對 ASCII 與中文相同,對 emoji 差 7 倍——實跑探針: 「👨👩👧👦」characters=1 runes=7;maxLength: 5 放行了 35 個 rune。 於是評分畫面計數器顯示「200/200 沒超過」、送出卻被後端以 400 擋下,而錯誤訊息 (「評論長度超過上限」)不會說上限是多少,對照計數器只會更困惑。 六個欄位:評分評論 200/遺失物描述 300/預約備註 200 三個單位錯; 聊天訊息 500/常用地點名稱 40 兩個完全沒擋;常用地點地址唯讀,刻意不加限制器 ——它由地圖選點反查填入,客戶端截短會產生**錯的地址**,司機會開到別的地方。 修法:共用 RuneLimitingTextInputFormatter + runeCounter,擋的單位與顯示的數字 都與後端一致。裁切落在 cluster 邊界而不是直接砍 rune 陣列——從 ZWJ 序列中間切 會留下半個字。maxLength 只留著讓 Flutter 畫計數器的位置,強制交給 formatter。 驗收:flutter analyze 無 issue、flutter test 434 passed(425+新 9)、 flutter build apk --debug --flavor customer 成功。 反向驗證兩個半邊各一次:拿掉聊天的 formatter → 700 rune 整段進得去該案 FAIL; 把限制器改回數 cluster → 5 案 FAIL。 另有一案專驗「真畫面接上去了」(常用地點開表單→輸入 30 面旗子→只留 20 面、 計數器顯示 40/40)——只驗共用元件的話,某個畫面漏接 inputFormatters 不會變紅。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
本輪掃的族
跨端輸入邊界對帳——App 的欄位上限 vs 後端 validator。從沒掃過,掃出來的東西比預期硬:不只有三個欄位沒擋,有擋的那三個擋的單位也是錯的。
根因一句話
Flutter 的
TextField.maxLength數的是 grapheme cluster(使用者感知的「一個字」),後端每一支上限數的都是 rune(utf8.RuneCountInString/len([]rune(...)))。對 ASCII 與中文相同,對 emoji 差到 7 倍。取證(不是查文件,是實跑探針)
maxLength: 5放行了 35 個 rune。於是評分畫面的計數器顯示「200/200 沒超過」,送出卻被後端以 400 擋下——而錯誤訊息(「評論長度超過上限」)不會說上限是多少,對照著計數器看只會更困惑。六個欄位的對帳表
ratingCommentMaxRunes200maxLength: 200(數 cluster)lostItemDescMaxRunes300maxLength: 300(數 cluster)maxScheduleNoteRunes200maxLength: 200(數 cluster)chatMaxRunes500maxPlaceLabelRunes40maxPlaceAddressRunes200修法
RuneLimitingTextInputFormatter+runeCounter():擋的單位與顯示的數字都與後端一致。maxLength只留著讓 Flutter 畫出計數器的位置,強制交給 formatter(maxLengthEnforcement: none)——兩套同時生效會先被 cluster 那套擋掉。x/500太吵,而 500 字平常打不到。驗收
flutter analyze無 issue、flutter test434 passed(425 +新 9)、55 個測試檔。maxLength的行為)→ 5 案 FAIL。40/40)——只驗共用元件本身的話,某個畫面漏接inputFormatters不會有任何測試變紅。flutter build apk --debug --flavor customer -t lib/main_customer.dart成功。誠實說明沒做到的
遺失物描述/預約備註/評分評論三個畫面沒有各自的「真畫面接上去了」測試(只有常用地點與聊天室有)。三個接法完全相同、
analyze也綠,但嚴格說它們的接線目前靠 review 不靠測試。已寫進 TODO 的「同族還沒碰的角落」,條件是下次動到那三個畫面時順手補。開工前的例行實查(第九次)
三個外部卡點依然都不在(
android/app/google-services.json、ios/Runner/GoogleService-Info.plist不存在、xcrun devicectl list devices→ No devices found);開工時三個 repo 的 open PR 皆為 0。🤖 Generated with Claude Code