1. Анализ принципа обработки ошибок
В веб-проекте, созданном с помощью SpringBoot, когда запрошенная нами страница не существует (код состояния HTTP — 404) или когда возникает исключение (код состояния HTTP обычно равен 500), SpringBoot вернет нам сообщение об ошибке.
Другими словами, в веб-проекте SpringBoot автоматически создается интерфейс ошибки /error для возврата информации об ошибке. Однако для разных методов доступа будут следующие две разные возвращаемые данные. Это в основном зависит от информации заголовка http при посещенииAccept
Это значение указывает, какие типы вы можете получать
- Информация заголовка и возвращаемый результат при доступе с помощью браузера
Accept: text/html
- Используйте другие устройства, такие как мобильные клиенты, для доступа к информации о заголовке и его возвращаемых результатах (обычно в разделенной архитектуре внешнего и внутреннего интерфейса).
Accept: */*
2. Обработка ошибок
Существует два основных способа обработки исключений:
1. Обработка исключений с использованием принципа автоконфигурации SpringBoot
SpringBoot автоматически настраивает классErrorMvcAutoConfiguration
Чтобы обрабатывать исключения, вы можете посмотреть, если вам интересно, а затем определить ошибочный класс BasicErrorController в этом классе.Основной код выглядит следующим образом:
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
/**
* 错误的页面响应
*/
@RequestMapping(produces = {"text/html"})
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
// 得到一个modelAndView对象
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}
/**
* 错误的json响应
*/
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = this.getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity(status);
} else {
Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
return new ResponseEntity(body, status);
}
}
}
Я не буду вдаваться в слишком много кода, и если вам интересно, вы можете взглянуть. Приведенный выше код означает, что для разных методов запроса будут возвращены разные результаты.@RequestMapping
аннотированныйproduces = {"text/html"}
атрибут
1), вернуть страницу с ошибкой, например 404, 500 и т. д.
-
В случае механизма шаблонов (который можно использовать для рендеринга страниц)
В качестве рендеринга страницы в проекте используются шаблонизаторы, такие как: thymeleaf, freemarker и т.д. Создайте папку /error в шаблонах и добавьте файл .html, соответствующий коду состояния ошибки, как показано ниже:
404 и 500 здесь являются определенными кодами состояния ошибки, а 4xx указывает на другие ошибки, начинающиеся с 4, такие как 400, 401 и т. д. Конечно, вы можете установить соответствующую страницу ошибки для каждого кода состояния, но в этом нет никакой пользы, поэтому вместо этого вы можете напрямую использовать общую ссылку, такую как 4xx.html.
На нашей странице ошибки можно получить следующую информацию (то есть содержимое объекта ModelAndView):
имя поля | иллюстрировать |
---|---|
timstamp | отметка времени |
status | код состояния ошибки |
error | Сообщение об ошибке |
exception | объект исключения |
message | Ненормальное сообщение |
path | путь к странице |
Внимательные друзья обнаружат, что это на самом деле содержимое json, которое возвращается, когда вы запрашиваете его с помощью своего мобильного телефона.
Например: добавьте вышеуказанную информацию в код, а затем пропишите код ошибки в бэкенде:
@RequestMapping("haserror")
@ResponseBody
public Object myError(){
int i =10/0;
return "something is error";
}
这是一个错误页面:
<ul>
<li>错误状态码:[[${status}]]</li>
<li>错误消息:[[${error}]]</li>
<li>异常对象:[[${exception}]]</li>
<li>异常消息:[[${message}]]</li>
<li>当前时间:[[${timestamp}]]</li>
</ul>
-
Без шаблонизатора
Когда движок шаблонов не используется в проекте, просто переместите всю папку ошибок в папку static.
Однако указанную выше информацию нельзя получить в настоящее время, так как это статический ресурс и нет механизма шаблонов для рендеринга.
2) и возвращает соответствующую строку json
По этому поводу сказать нечего, возвращается строка json. Формат следующий:
{
"timestamp": "2020-04-22T16:13:37.506+0000",
"status": 500,
"error": "Internal Server Error",
"message": "/ by zero",
"path": "/hello/haserror",
"reason": "完了,你写的代码又产生了一次线上事故"
}
3), информация о возврате пользовательской страницы
Это самый важный контент, потому что эта информация не только возвращается в виде json, но также может быть получена на странице с ошибкой выше или может быть возвращена напрямую в формате json. На самом деле это очень просто, то есть добавитьErrorAttributes
С объектом все в порядке, здесь я решил наследовать его подкласс.
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
//调用父类的方法,会自动获取内置的那些属性,如果你不想要,可以不调用这个
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
//添加自定义的属性
errorAttributes.put("reason","完了,你写的代码又产生了一次线上事故");
// 你可以看一下这个方法的参数webRequest这个对象,我相信你肯定能发现好东西
return errorAttributes;
}
}
Вот и все, проверьте, доступно ли одно из наших пользовательских свойств в двух методах запроса:
2. Используйте уведомление об исключении AOP для обработки (рекомендуется)
Его принцип заключается в том, чтобы получить глобальное уведомление об исключении и затем обработать его. Нам нужно только написать следующий код в проекте (на самом деле, это просто класс для пользовательской информации об исключении)
@ControllerAdvice
public class ErrroAcvice {
/**
* 全局捕获异常的切面类
* @param request 请求对象,可不传
* @param response 响应对象,可不传
* @param e 异常类(这个要和你当前捕获的异常类是同一个)
*/
@ExceptionHandler(Exception.class) //也可以只对一个类进行捕获
public void errorHandler(HttpServletRequest request, HttpServletResponse response,Exception e){
/*
* You can do everything you want to do
* 这里你拿到了request和response对象,你可以做任何你想做的事
* 比如:
* 1.用request从头信息中拿到Accept来判断是请求方可接收的类型从而进行第一个方法的判断
* 2.如果你也想返回一个页面,使用response对象进行重定向到自己的错误页面就可以了
* 3.你甚至还拿到了异常对象
*/
String accept = request.getHeader("Accept");
// 根据这个字符串来判断做出什么响应
try {
response.setStatus(500);
response.getWriter().write("hello");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
3. Сравнение двух методов:
- Первый способ заключается в том, чтобы поместить несколько кодовых страниц состояния ошибки в текущий проект и позволить SpringBoot найти их. Также поддерживает настраиваемые возвращаемые сообщения об ошибках.
- Второй метод заключается в непосредственном использовании идеи АОП для обработки уведомлений об исключениях, что очень бесплатно.
- Я лично рекомендую использовать второй метод, потому что степень свободы высока, вы можете в любой момент внести изменения в соответствии с собственной бизнес-логикой, и в этом есть большая польза. В следующей статье будет хороший пример
- После использования второго метода страницы ошибок и пользовательские сообщения об ошибках, размещенные первым методом, становятся недействительными.