表单输入字段处理包含非预期的字符

html / java / spring

遇到一个有意思的事情,springboot 收到表单 radio 字段的值中包含了`, on`字样,刚开始原因不明,迫于时间紧迫用 int 类型规避了这个问题,后来有时间仔细研究了一下,还是自己犯的错误

1 重现

我们用以下表单就可以重现这个问题

<form th:action="@{form}" method="POST">
  <h5>this is a form</h5>

  <input id="form-input-radio-cat-1" type="radio" name="cat" value="1" />
  <label for="form-input-radio-cat-1"> 类别 1</label>
  <input id="form-input-radio-cat-2" type="radio" name="cat" value="2" />
  <label for="form-input-radio-cat-2"> 类别 2</label>

  <input type="checkbox" name="cat" required /> 确认无误
  <button type="submit">submit</button>
</form>

明眼的同学应该一下子就发现问题所在了,这是一个简化的例子,实际的表单要更复杂,所以比较难看出。没看出来的同学也不用着急,往下读,我们的表单类也比较简单

public class DemoForm {
    private String cat;

    public String getCat() {
	return cat;
    }

    public void setCat(String cat) {
	this.cat = cat;
    }
}

如果我们选中类别 2、勾选确认无误,提交表单,然后在 Controller 中打印 cat 的值,会得到如下结果:

TestController     : form cat: 2,on

2 规避

由于我没有看出来表单中的错误,所以这个问题困扰了我一些时间,而且由于时程的压力,当时没有很多精力投入到问题的排查中,很快我想到了一个规避的方法:使用 int 类型,这样我们的 DemoForm 就变成这个样子:

public class DemoForm {
    private int cat;

    public int getCat() {
	return cat;
    }

    public void setCat(int cat) {
	this.cat = cat;
    }
}

由于 parse 的时候会忽略 ",on" 这部分内容,所以运行时不会有其他问题,当然这个 ",on" 怎么来的,我们也就无从知道了。

3 后端排查

由于我「自认为」已经检查过表单,认为前端表单提交不会有问题,并且怀疑是不是因为选中了「类别2」,出于某种机制,springboot 自动加上了该标记,所以很自然的开始从后端排查起来。

几次断点后,大概知道,这个值是从 MutablePropertyValues mpvs 而来,mpvs 中, cat 的值是一个数组:[“2”, “on”] ,而 mpvs 又来自 ServletRequest request ,那么问题大概可以猜到了,post 的数据很可能传递了两个 cat 的值,我们可以从 request 中检查 postData, 不过我觉得另一个方法更简单

4 前端排查

提交表单前打开浏览器的开发者模式,检查表单数据就好了

5 结论

问题已经很清楚了,前端表单多标注了一个 cat,导致 cat 的值变成了数组,知道了问题,那么修改起来也很简单,去掉相应的 name 属性即可:

<form th:action="@{form}" method="POST">
  <h5>this is a form</h5>

  <input id="form-input-radio-cat-1" type="radio" name="cat" value="1" />
  <label for="form-input-radio-cat-1"> 类别 1</label>
  <input id="form-input-radio-cat-2" type="radio" name="cat" value="2" />
  <label for="form-input-radio-cat-2"> 类别 2</label>

  <input type="checkbox" required /> 确认无误
  <button type="submit">submit</button>
</form>