一、引言

本篇内容是“异常统一处理”系列文章的重要组成部分,主要聚焦于对 HttpRequestMethodNotSupportedException 的原理解析与异常处理机制,并给出测试案例。

二、异常原理

在Spring Boot应用中,HttpRequestMethodNotSupportedException异常是由Spring MVC框架抛出的,当客户端通过HTTP协议发送请求到服务器端时,所使用的HTTP方法(如GET、POST、PUT、DELETE等)与控制器方法所期望的方法不匹配时,就会触发这个异常。

例如,如果你有一个只支持POST请求的RESTful API接口:

@PostMapping("/some-resource")
public ResponseEntity<String> handlePostRequest(...) {
    // ...
}

但客户端尝试以GET方法访问该资源:

GET /some-resource

此时,由于服务器端没有为GET方法配置对应的处理方法,Spring MVC在解析请求并试图找到合适的方法进行处理时,无法找到对应HTTP GET方法的处理器,因此会抛出HttpRequestMethodNotSupportedException异常,并附带信息说明请求的方法不受支持。

解决这个问题的方式是确保客户端使用与服务器端定义的控制器方法相匹配的HTTP方法进行通信。如果需要支持多种HTTP方法,可以使用@RequestMapping注解配合method属性指定多个支持的方法,或者分别使用@GetMapping@PostMapping等注解来明确指定每个HTTP方法的处理器方法。

三、异常处理代码

在Spring Boot应用中,我们可以通过使用@ExceptionHandler注解来捕获并处理HttpRequestMethodNotSupportedException异常。

3.1 异常处理示意图

在这里插入图片描述

3.2 异常处理核心代码

异常处理策略的核心代码如下:

package com.example.core.advice;

import com.example.core.advice.util.ApiUtil;
import com.example.core.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    private final HttpServletRequest request;

    public GlobalExceptionHandler(HttpServletRequest request) {
        this.request = request;
    }

    /**
     * Http请求方法不支持异常。
     * <p>
     * 一个接口,是由【请求方法】(GET、POST、PUT、DELETE等)和【接口路径】两个部分来唯一确定的。
     * 当一个请求,能找到对应的【接口路径】,但是没有找到对应的【请求方法】时,会报异常 HttpRequestMethodNotSupportedException ,进入此异常处理。
     * 当一个请求,找不到对应的【接口路径】时,会直接报错 404 ,不会进入此异常处理。
     * <p>
     * 测试:一个接口,应该用Post请求,却用了GET请求。
     * <p>
     * 报错示例:
     * DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported]
     * <p>
     * 注意:此方法不能包含 HandlerMethod 入参,否则会报错;因为进入此异常处理方法,意味着收到的请求是没有对应的控制器方法的。
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Result<String> handle(HttpRequestMethodNotSupportedException e) {
        String api = ApiUtil.getApi(request);
        String userMessage = "Http请求方法不支持异常!请稍后重试,或联系业务人员处理。";
        String errorMessage = String.format("HttpRequestMethodNotSupportedException(Http请求方法不支持异常);当前请求接口:[%s];报错信息:%s", api, e.getMessage());
        return Result.fail(userMessage, String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value()), errorMessage);
    }

}

上述代码中,当出现HttpRequestMethodNotSupportedException异常时,系统将返回一个状态码为405(Method Not Allowed)的结果,并附带具体的错误信息。

3.3 获取当前请求的API

package com.example.core.advice.util;

import javax.servlet.http.HttpServletRequest;

/**
 * API工具类
 *
 * @author songguanxun
 * @since 2024-2-18
 */
public class ApiUtil {

    /**
     * 获取当前请求的API
     */
    public static String getApi(HttpServletRequest request) {
        String method = request.getMethod();
        String uri = request.getRequestURI();
        return String.format("%s %s", method, uri);
    }

}

四、测试案例

4.1 测试代码

package com.example.web.exception.controller;

import com.example.web.model.param.UserAddParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@Slf4j
@RestController
@RequestMapping("exception")
@Tag(name = "异常统一处理")
public class ExceptionController {

    @PostMapping("HttpRequestMethodNotSupportedException")
    @Operation(summary = "异常:HttpRequestMethodNotSupportedException")
    public void testHttpRequestMethodNotSupportedException(@Valid @RequestBody UserAddParam param) {
        log.info("测试:HttpRequestMethodNotSupportedException");
    }

}

4.2 正确请求示例

在这里插入图片描述

4.3 未处理异常时的报错

请求响应

在这里插入图片描述

控制台的错误日志

在这里插入图片描述

4.4 已处理异常时的响应

在这里插入图片描述

五、触发异常的情景

如下示例中,当请求 删除用户 接口时,前端漏传id参数,导致接口路径变为 [/users];只有新增用户和查询用户列表的接口为 [/users],且请求方法都不是DELETE。最后,就抛出了 HttpRequestMethodNotSupportedException 异常,因为 接口路径[/users]不支持DELETE方法

当出现此种情况时,说明前端调用接口出现了错误,应检查前端请求代码,将id参数补全。

接口示例

在这里插入图片描述

请求示例

在这里插入图片描述

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐