规范-前、后台请求参数校验

1. 什么时候我们会前、后端校验?

正常情况下,前后端对于请求的参数都需要校验的,这能提高应用程序的稳定性、可维护性,而对于前后台如果能将这种不可缺少校验规则汇总并制定一套规范,在每一个应用程序中都使用这种规范,能给带来不少好处。那在哪些情况下适合使用前、后端校验了:

  • 应用程序业务单一、后期维护少、不涉及敏感信息,如:公司内部OA系统,这种系统可以直接使用前端校验,而这里的前端参数校验可以使用:H5表单校验或者封装常用校验JS文件。
  • 应用程序业务单一、后期维护少;如:支付系统,由于支付系统可能会有其他公司对接平台的接口,所有这种前端校验就交给其他公司了,我们只需要做好后端校验就行。
  • 业务复杂、后期维护多、安全可用性要求高,如:电商项目的维护,这种方式要同时使用前后端校验,前端校验的目的是为了把更多的错误请求都在浏览器层面就已经拦截处理,不会消耗服务端的内存和线程数,可以提供性能;对于还要进行后端校验是为了提高系统的稳定性,不要动不动就500,还能防止一些人恶意攻击网站等等。

2. 前端请求参数校验

常用的方式有这些:

  • 自己封装一个通用校验JS文件,统一校验方式(使用与JS发送请求)
  • H5标签属性检验方式(适用于web form表单提交)
  • 第三方JS自己封装的校验方法,这里对前端的建议尽量统一起来、规范起来。

3. 后端请求参数校验

常用的方式有这些:

  • 不校验,我对比了之前开发的一些小系统(外包)对于后端参数基本没有,这种方式的确可以做到后端开发快,所有的校验都交给前端做,但对于前端不友好,如:由于前端少传递一个参数,导致后端程序报错,而后端又没有提供详细的报错信息,这给前端对接带来了问题,前端不知道自己错在哪里,这个时候可能还的和后端人员进行沟通,后端看看Log再告诉前端,这种方式对于前端对接不友好并且效率低。
  • 封装自己的校验工具类进行检验,这种方式的确能做到后端交易,但如果需要校验的参数比较多对程序是不友好的,如:
  • 使用@RequestParam注解完成简单非空校验,这种虽然可以检验,但如果没有传此字段会抛出异常,这里需要通过全局异常捕获统一处理。
@RequestParam(value = "mobile", required = true) String mobile
  • 使用Interceptor、Filter、Aop.. 做公共部分的业务做统一的校验处理,如:Token检验,权限校验..
  • 如果需要校验的参数比较多,校验方式和业务代码混合在一块不方便于代码的维护,可以使用hibernate-validator来做分组校验。

虽然到这里通过hibernate-validator来做分组校验就可以解决所有方式的参数校验:

但也存在问题,后端校验的确做到了,但如果要将这些参数校验都编写到接口文档中,这个时候我们还需要先找接口、找到分组、找到dto下分组对应的所有参数校验,增加参数校验规则还得重新修改接口文档等等。

4. 后端参数校验总结

目前后端校验基本就是上面我提到的几种常用方式,但这些方式都有缺点,基本上hibernate-validator已经算是比较好的了,所以这里推荐使用(适用于大部分项目),使用hibernate-validator也存在问题,就是接口文档编写,这里引入一个接口管理框架swagger,swagger可以统一管理api并将api提供给前端人员,swagger目前可以做到通过编写yaml文件,根据yaml中的参数必填的属性配置,可以通过yaml生成对应的接口代码且接口代码中已经做了参数校验,以后对于参数校验可以直接修改yaml文件并重新生成就行了,同时yaml还可以直接提供给前端人员做mock或生成接口文档。对于yaml生成后端代码,我会在后面的博客继续提到,这里只简单提到对于hibernate-validator文档管理痛点引入的swagger yaml生成后端代码。

基于yaml生成的后端代码:

    public ResponseEntity<ApiCommonResultVo> loginUsingPOST(@NotNull @ApiParam(value = "账号", required = true) @Valid @RequestParam(value = "mobile", required = true) String mobile,@NotNull @ApiParam(value = "密码", required = true) @Valid @RequestParam(value = "password", required = true) String password) {
        String accept = request.getHeader("Accept");
        if (accept != null && accept.contains("")) {
            try {
                return new ResponseEntity<ApiCommonResultVo>(objectMapper.readValue("", ApiCommonResultVo.class), HttpStatus.NOT_IMPLEMENTED);
            } catch (IOException e) {
                log.error("Couldn't serialize response for content type ", e);
                return new ResponseEntity<ApiCommonResultVo>(HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }
        log.info("login success...");
        return new ResponseEntity<ApiCommonResultVo>(HttpStatus.NOT_IMPLEMENTED);
    }

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券