处理Spring Boot中嵌入的Tomcat异常

0md85ypi  于 2022-10-04  发布在  Spring
关注(0)|答案(2)|浏览(240)

我们遇到了嵌入式Tomcat从LegacyCookieProcessor抛出IllegalArgumentException的问题。它抛出500个HTTP响应代码。

我们需要处理该异常并对其执行某些操作(具体地说,改为将其作为400发送)。

典型的@ExceptionHandler(IllegalArgumentException.class)似乎不会被触发,而Google似乎只给出了处理Spring Boot特定异常的结果。

示例:

这里有一个重现这一行为的例子。您可以通过下载2.1.5.RELEASE版本中的初始项目来执行该示例,其中包括Spring-web(https://start.spring.io/)。然后向您的项目添加以下两个类。
DemoControllerAdvice.java

package com.example.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class DemoControllerAdvice {

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Map<String, String> forbiddenHandler() {
        Map<String, String> map = new HashMap<>();
        map.put("error", "An error occurred.");
        map.put("status", HttpStatus.FORBIDDEN.value() + " " + HttpStatus.FORBIDDEN.name());
        return map;
    }

}

DemoRestController.java

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoRestController {

    @GetMapping(value = "/working")
    public void working() {
        throw new java.lang.IllegalArgumentException();
    }

    @GetMapping(value = "/not-working")
    public String notWorking(@RequestParam String demo) {
        return "You need to pass e.g. the character ^ as a request param to test this.";
    }

}

然后,启动服务器并在浏览器中请求以下URL:

  • http://localhost:8080/working在控制器中手动抛出IllegalArgumentException。然后,它被ControllerAdance捕获,因此将生成一个包含DemoControllerAdvice中定义的信息的JSON字符串
  • http://localhost:8080/not-working?demo=test^123 Tomcat抛出IllegalArgumentException,因为无法解析请求参数(因为字符^无效)。但是,ControllerAdvices不会捕获该异常。它显示了Tomcat提供的默认HTML页面。它还提供与DemoControllerAdvice中定义的不同的错误代码。

在日志中显示以下消息:
O.apache.coyote.http11.Http11Processor:解析HTTP请求标头时出错注意:将在调试级别记录进一步出现的HTTP请求解析错误。

Java.lang.IlLegalArgumentException:请求目标中发现无效字符。有效字符在org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:467)~[TOMCAT-EMBED-CORE-9.0.19.jar:9.0.19]的RFC7230和RFC3986中定义

vyu0f0g1

vyu0f0g11#

这是Tomcat本身的一个特性,如this答案中所述。

但是,您可以通过允许将您期望的特殊字符作为请求的一部分并自己处理它们来执行类似的操作。

首先,您需要这样设置relasedQueryChars,从而允许您需要处理的特殊字符。

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class TomcatCustomizer implements 
WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

@Override
public void customize(TomcatServletWebServerFactory factory) {
    factory.addConnectorCustomizers((connector) -> {
        connector.setAttribute("relaxedQueryChars", "^");
    });
 }
}

然后处理每个请求中的特殊字符,或者创建一个拦截器并在公共位置处理它。

要在请求中单独处理它,您可以这样做。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoRestController {

@GetMapping(value = "/working")
public void working() {
    throw new java.lang.IllegalArgumentException();
}

@GetMapping(value = "/not-working")
public String notWorking(@RequestParam String demo) {

    if (demo.contains("^")) {
        throw new java.lang.IllegalArgumentException("^");
    }
    return "You need to pass e.g. the character ^ as a request param to test this.";
}

}

您可能还想参考this答案,以确定是否真的需要此修复。

bvjveswy

bvjveswy2#

尝试在您的过滤器中捕获IllegalArgumentException,然后调用HttpServletResponse.sendError(int sc, String msg);。不过,这可能会捕获不是来自Tomcat的e1d2d1。但我想你已经很好地处理它们了。

相关问题