前端——前端传个空字符串,后端Long类型直接崩溃?这个坑我帮你填了!

张开发
2026/4/18 21:02:56 15 分钟阅读

分享文章

前端——前端传个空字符串,后端Long类型直接崩溃?这个坑我帮你填了!
一个看似不起眼的空字符串差点让我加班到深夜…一次“莫名其妙”的接口报错上周正在开发一个表单提交功能测试同学突然来找我“保存草稿按钮点不了接口报错了。”我打开浏览器控制台看到请求返回了这样一个错误json{ code: 500, msg: 参数JSON格式错误, ok: false }JSON格式错误我仔细检查了请求参数发现数据是这样的json{ formId: 1001, title: 测试表单, categoryId: , departmentId: , items: [...] }等等categoryId和departmentId怎么是空字符串明明页面上这两个字段都没选啊。问题就出在这里了。为什么会崩溃后端接口的定义大概是这样的javaData public class FormSubmitDTO { private Long formId; private String title; private Long categoryId; // 看好了这是 Long 类型 private Long departmentId; // 这也是 Long 类型 }真相只有一个Java 的 Jackson 库在反序列化 JSON 时无法把空字符串转换成Long类型于是直接抛了异常。一张表看懂各种空值情况前端传的值后端字段类型结果nullLong✅ 正常值为nullLong❌ 崩溃JSON解析错误100Long✅ 正常值为100L100Long✅ 正常值为100L不传该字段Long✅ 正常值为nullString✅ 正常值为Integer❌ 崩溃核心结论所有数值类型Long、Integer、Double、BigDecimal 等都无法接受空字符串。解决方案由简到繁方案一前端统一清洗数据强烈推荐写一个递归函数在提交前把所有的空字符串转成nulljavascript// 清洗函数空字符串 - null function cleanEmptyValues(obj) { const result {} for (const [key, value] of Object.entries(obj)) { if (value ) { result[key] null // 关键一步 } else if (Array.isArray(value)) { result[key] value.map(item typeof item object ? cleanEmptyValues(item) : item ) } else if (typeof value object value ! null) { result[key] cleanEmptyValues(value) } else { result[key] value } } return result } // 使用示例 const submitData cleanEmptyValues({ formId: 1001, title: 测试表单, categoryId: , // 变成 null departmentId: , // 变成 null }) await api.submit(submitData)方案二只处理特定字段简单场景如果只有一两个字段需要处理直接写逻辑就行javascript// 最简单的写法 const submitData { formId: form.formId, title: form.title, categoryId: form.categoryId || null, // 空字符串或 undefined 都转 null departmentId: form.departmentId || null, } // 注意如果 0 是有效值用这个更安全 const submitData { categoryId: form.categoryId ? null : form.categoryId, }方案三封装到请求拦截器一劳永逸javascript// axios 请求拦截器 axios.interceptors.request.use(config { if (config.data) { config.data cleanEmptyValues(config.data) } return config })方案四后端配置不推荐理论上可以让后端配置 Jackson 来兼容空字符串但我不推荐java// 不推荐这样做 mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);为什么不推荐改变了全局行为可能影响其他正常接口掩盖了前端的问题不利于排查前端传正确的数据类型才是正道如何预防这个问题1. 表单初始化用 null 而不是空字符串javascript// ❌ 坏习惯 const form reactive({ categoryId: , departmentId: }) // ✅ 好习惯 const form reactive({ categoryId: null, departmentId: null })2. 下拉选择器清空时设为 nullvuetemplate Select v-modelform.categoryId clearable clearform.categoryId null !-- 关键 -- / /template3. TypeScript 类型约束typescriptinterface FormData { formId: number title: string categoryId: number | null // 明确允许 null departmentId: number | null } const form: FormData { categoryId: null, // ✅ // categoryId: , // ❌ 类型错误编译就报错 }常见踩坑场景场景一表单重置javascript// ❌ 问题代码 function resetForm() { form.categoryId } // ✅ 正确代码 function resetForm() { form.categoryId null }场景二URL 参数解析javascript// URL: /page?categoryId const categoryId route.query.categoryId // 结果是 // ❌ 直接传会报错 // ✅ 处理一下 const categoryId route.query.categoryId || null场景三UI 组件库的坑很多 UI 组件库的清空功能返回的是空字符串而不是null需要手动处理。总结记住这一条原则就够了数值类型的空值用null别用空字符串最佳实践清单✅ 表单数据初始化用null✅ 提交前统一清洗空字符串✅ 选择器清空时手动设为null✅ 使用 TypeScript 做类型约束❌ 不要依赖后端兼容空字符串这个坑其实很小但就是容易忽略。希望这篇文章能帮你少加一次班如果你也遇到过类似的问题欢迎在评论区分享你的解决方案~

更多文章