如何应对spring框架的HTTP ERROR 400 Bad Request错误返回

HTTP ERROR 400 Bad Request 产生的流程

在使用springmvc相关的框架的时候,调用接口经常产生以下错误
调用接口经常产生的错误
这种错误往往在infolog级别下看不到日志,难以排查,我们先来模拟错误产生的其中一个原因

从spring框架的入口FrameworkServlet开始找

  1. 假设我们的接口使用get请求,则从doGet里面的processRequest方法开始调式,并且假设模拟一个请求类型不匹配的参数,比如需要一个int类型的参数但是传一个字符串。
    需要一个int类型的参数但是传一个字符串
    processRequest

  2. 下一步进入doDispatch方法
    doDispatch

  3. 进入接口对应方法的处理,使用handler处理
    handler

  4. 进入到实际调用的方法的代码,invokeHandleMethod,在调用此方法的时候,会先做一些参数的校验,如是否空值(MissingServletRequestParameterException)、是否类型匹配(TypeMismatchException)、媒体类型是否支持(HttpMediaTypeNotSupportedException)等
    invokeHandleMethod

  5. 进入invokeForRequest方法
    invokeForRequest

  6. 进入getMethodArgumentValues方法,此方法用来获取处理接口实际方法的参数和值的对应关系。可以看到在这个地方产生了错误,并且向上一级抛出了异常且异常被doDispatch捕获,然后进入processDispatchResult方法处理返回的结果
    getMethodArgumentValues
    异常被doDispatch捕获

  7. 调用HandlerExecutionChain的异常处理方法去处理异常
    HandlerExecutionChain处理异常

  8. 调用resolveException处理,处理的时候是循环使用List<HandlerExceptionResolver> resolvers中的所有的handlerExceptionResolver依次处理,如果处理成功则返回。可以看到一共有5个handlerExceptionResolver,本次接口调用被第二个handlerExceptionResolver处理成功并返回在这里插入图片描述DefaultHandlerExceptionResolver处理

  9. 异常被成功处理
    异常被doResolveException成功处理

  10. 返回错误码和空ModelAndView
    返回错误码和空ModelAndView

  11. requestAttribute属性中设置异常信息
    在request的attr属性中设置异常信息

  12. 进行handler的后置处理,比如执行HandlerInterceptorafterCompletion方法
    afterCompletion后置处理

  13. 执行processRequestfinally中的剩余代码逻辑
    processRequest剩余代码逻辑

HTTP ERROR 400 Bad Request 产生的原因

由于在以上代码中调用了

		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
		return new ModelAndView();

导致产生了400页面

400错误为什么不能被自定义的异常处理器捕获并且处理

由于handlerExceptionResolvers要按顺序依次执行并且执行成功后就立即返回后续的将不再执行,我们自定义的handlerExceptionResolvers排在List的最后(由上图可以很清晰的知道,我们自定义的WebExceptionHandler排在最后),所以,轮不到它处理,spring就内部就将异常消化处理好了。

为什么不能自己定制输出内容

response.sendError(HttpServletResponse.SC_BAD_REQUEST)

上面的代码已经使用了response将结果写入到输出流,所以后续将无法使用response或者类似于

PrintWriter out = null;
        try {
            out = response.getWriter();
            Map<String,Object> result = new HashMap<String, Object>();
            result.put("code",be.getErrorCode());
            result.put("message",be.getMessage());
            out.write(JSONObject.toJSONString(result));
            out.flush();
        } catch (IOException e) {
            
        } finally {
            if (out != null) {
                out.close();
                out = null;
            }
        }

的方式自定义输出

目前可以做的

研究了一番,发现不能自定义输出(或者有其他的好方法没发现),所以只能记录下错误日志并且打印出来,这样就不会稀里糊涂了

  • 未加日志之前
    未加日志之前
  • 加日志之后
    加日志之后1

加日志之后2

  • 如何加日志
    通过以上的代码分析可知,spring会将异常写入到requestAttribute属性中,所以只需要
Object attribute = request.getAttribute(DispatcherServlet.class.getName() + ".EXCEPTION");

就可以获得异常信息了,并且在自己的Filter里面打印,这样就不会在产生400之类类似的错误的时候一头雾水了

原创文章,转载请表明出处
https://blog.youkuaiyun.com/starryninglong/article/details/108828672

### HTTP 'Bad Request' 错误原因 HTTP 400 Bad Request 是一种客户端错误状态码,表示服务器无法处理请求,因为请求本身存在语法错误或不被理解。常见原因包括: - 请求URL格式不正确,可能含有非法字符或路径[^1]。 - AJAX请求中携带的数据不符合预期格式,导致服务器端解析失败[^2]。 - 参数传递过程中出现问题,比如Spring MVC框架下GET请求中的查询字符串编码不当,或是某些必填字段缺失[^3]。 ### 解决方案 针对上述提到的不同场景下的`Bad Request`问题,可以采取以下措施来尝试解决问题: #### 对于CDN配置引起的400错误 当迁移至带有CDN加速的服务时遇到此类情况,应仔细检查并调整CDN设置以及源站之间的交互逻辑,确保所有资源链接的有效性和合法性。特别是注意审查重定向规则、缓存策略等方面是否存在潜在冲突。 ```bash curl -I http://your-cdn-url/image.jpg ``` 通过命令行工具如`curl`获取响应头信息可以帮助诊断具体的错误位置。 #### 处理AJAX请求引发的400错误 对于前端发起的异步调用来说,确认发送给后端接口的内容类型(Content-Type)、消息体结构均满足API文档的要求至关重要。如果采用JSON作为传输介质,则需保证对象序列化无误;若是表单提交方式,则要留意边界符等细节之处。 ```javascript $.ajax({ url: '/api/example', type: 'POST', contentType: 'application/json;charset=UTF-8', // 明确指定内容类型 data: JSON.stringify({ key: value }), // 序列化JavaScript对象为JSON字符串 }); ``` #### SpringMVC应用内的400错误排查 在Java Web应用程序开发环境下,尤其是基于Spring框架构建RESTful API的情况下,应当关注控制器层的方法签名设计合理性——即入参映射机制能否顺利工作。此外,还需考虑浏览器地址栏直接访问带参数页面是否会触发异常情形的发生。 ```java @GetMapping("/example") public ResponseEntity<?> getExample( @RequestParam(value="param", required=false) String param){ ... } ``` 以上代码片段展示了如何利用@RequestParam注解灵活控制可选查询项的存在与否,从而减少因缺少必要输入而导致的整体流程中断风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值