001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.mvc.support; 018 019import java.io.IOException; 020import java.util.List; 021 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028import org.springframework.beans.ConversionNotSupportedException; 029import org.springframework.beans.TypeMismatchException; 030import org.springframework.core.Ordered; 031import org.springframework.http.MediaType; 032import org.springframework.http.converter.HttpMessageNotReadableException; 033import org.springframework.http.converter.HttpMessageNotWritableException; 034import org.springframework.lang.Nullable; 035import org.springframework.util.CollectionUtils; 036import org.springframework.util.StringUtils; 037import org.springframework.validation.BindException; 038import org.springframework.validation.BindingResult; 039import org.springframework.web.HttpMediaTypeNotAcceptableException; 040import org.springframework.web.HttpMediaTypeNotSupportedException; 041import org.springframework.web.HttpRequestMethodNotSupportedException; 042import org.springframework.web.bind.MethodArgumentNotValidException; 043import org.springframework.web.bind.MissingPathVariableException; 044import org.springframework.web.bind.MissingServletRequestParameterException; 045import org.springframework.web.bind.ServletRequestBindingException; 046import org.springframework.web.bind.annotation.ModelAttribute; 047import org.springframework.web.bind.annotation.RequestBody; 048import org.springframework.web.bind.annotation.RequestPart; 049import org.springframework.web.context.request.async.AsyncRequestTimeoutException; 050import org.springframework.web.multipart.MultipartFile; 051import org.springframework.web.multipart.support.MissingServletRequestPartException; 052import org.springframework.web.servlet.ModelAndView; 053import org.springframework.web.servlet.NoHandlerFoundException; 054import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; 055 056/** 057 * The default implementation of the {@link org.springframework.web.servlet.HandlerExceptionResolver} 058 * interface, resolving standard Spring MVC exceptions and translating them to corresponding 059 * HTTP status codes. 060 * 061 * <p>This exception resolver is enabled by default in the common Spring 062 * {@link org.springframework.web.servlet.DispatcherServlet}. 063 * 064 * <p> 065 * <table> 066 * <caption>Supported Exceptions</caption> 067 * <thead> 068 * <tr> 069 * <th class="colFirst">Exception</th> 070 * <th class="colLast">HTTP Status Code</th> 071 * </tr> 072 * </thead> 073 * <tbody> 074 * <tr class="altColor"> 075 * <td><p>HttpRequestMethodNotSupportedException</p></td> 076 * <td><p>405 (SC_METHOD_NOT_ALLOWED)</p></td> 077 * </tr> 078 * <tr class="rowColor"> 079 * <td><p>HttpMediaTypeNotSupportedException</p></td> 080 * <td><p>415 (SC_UNSUPPORTED_MEDIA_TYPE)</p></td> 081 * </tr> 082 * <tr class="altColor"> 083 * <td><p>HttpMediaTypeNotAcceptableException</p></td> 084 * <td><p>406 (SC_NOT_ACCEPTABLE)</p></td> 085 * </tr> 086 * <tr class="rowColor"> 087 * <td><p>MissingPathVariableException</p></td> 088 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td> 089 * </tr> 090 * <tr class="altColor"> 091 * <td><p>MissingServletRequestParameterException</p></td> 092 * <td><p>400 (SC_BAD_REQUEST)</p></td> 093 * </tr> 094 * <tr class="rowColor"> 095 * <td><p>ServletRequestBindingException</p></td> 096 * <td><p>400 (SC_BAD_REQUEST)</p></td> 097 * </tr> 098 * <tr class="altColor"> 099 * <td><p>ConversionNotSupportedException</p></td> 100 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td> 101 * </tr> 102 * <tr class="rowColor"> 103 * <td><p>TypeMismatchException</p></td> 104 * <td><p>400 (SC_BAD_REQUEST)</p></td> 105 * </tr> 106 * <tr class="altColor"> 107 * <td><p>HttpMessageNotReadableException</p></td> 108 * <td><p>400 (SC_BAD_REQUEST)</p></td> 109 * </tr> 110 * <tr class="rowColor"> 111 * <td><p>HttpMessageNotWritableException</p></td> 112 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td> 113 * </tr> 114 * <tr class="altColor"> 115 * <td><p>MethodArgumentNotValidException</p></td> 116 * <td><p>400 (SC_BAD_REQUEST)</p></td> 117 * </tr> 118 * <tr class="rowColor"> 119 * <td><p>MissingServletRequestPartException</p></td> 120 * <td><p>400 (SC_BAD_REQUEST)</p></td> 121 * </tr> 122 * <tr class="altColor"> 123 * <td><p>BindException</p></td> 124 * <td><p>400 (SC_BAD_REQUEST)</p></td> 125 * </tr> 126 * <tr class="rowColor"> 127 * <td><p>NoHandlerFoundException</p></td> 128 * <td><p>404 (SC_NOT_FOUND)</p></td> 129 * </tr> 130 * <tr class="altColor"> 131 * <td><p>AsyncRequestTimeoutException</p></td> 132 * <td><p>503 (SC_SERVICE_UNAVAILABLE)</p></td> 133 * </tr> 134 * </tbody> 135 * </table> 136 * 137 * @author Arjen Poutsma 138 * @author Rossen Stoyanchev 139 * @author Juergen Hoeller 140 * @since 3.0 141 * @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler 142 */ 143public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver { 144 145 /** 146 * Log category to use when no mapped handler is found for a request. 147 * @see #pageNotFoundLogger 148 */ 149 public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound"; 150 151 /** 152 * Additional logger to use when no mapped handler is found for a request. 153 * @see #PAGE_NOT_FOUND_LOG_CATEGORY 154 */ 155 protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY); 156 157 158 /** 159 * Sets the {@linkplain #setOrder(int) order} to {@link #LOWEST_PRECEDENCE}. 160 */ 161 public DefaultHandlerExceptionResolver() { 162 setOrder(Ordered.LOWEST_PRECEDENCE); 163 setWarnLogCategory(getClass().getName()); 164 } 165 166 167 @Override 168 @Nullable 169 protected ModelAndView doResolveException( 170 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 171 172 try { 173 if (ex instanceof HttpRequestMethodNotSupportedException) { 174 return handleHttpRequestMethodNotSupported( 175 (HttpRequestMethodNotSupportedException) ex, request, response, handler); 176 } 177 else if (ex instanceof HttpMediaTypeNotSupportedException) { 178 return handleHttpMediaTypeNotSupported( 179 (HttpMediaTypeNotSupportedException) ex, request, response, handler); 180 } 181 else if (ex instanceof HttpMediaTypeNotAcceptableException) { 182 return handleHttpMediaTypeNotAcceptable( 183 (HttpMediaTypeNotAcceptableException) ex, request, response, handler); 184 } 185 else if (ex instanceof MissingPathVariableException) { 186 return handleMissingPathVariable( 187 (MissingPathVariableException) ex, request, response, handler); 188 } 189 else if (ex instanceof MissingServletRequestParameterException) { 190 return handleMissingServletRequestParameter( 191 (MissingServletRequestParameterException) ex, request, response, handler); 192 } 193 else if (ex instanceof ServletRequestBindingException) { 194 return handleServletRequestBindingException( 195 (ServletRequestBindingException) ex, request, response, handler); 196 } 197 else if (ex instanceof ConversionNotSupportedException) { 198 return handleConversionNotSupported( 199 (ConversionNotSupportedException) ex, request, response, handler); 200 } 201 else if (ex instanceof TypeMismatchException) { 202 return handleTypeMismatch( 203 (TypeMismatchException) ex, request, response, handler); 204 } 205 else if (ex instanceof HttpMessageNotReadableException) { 206 return handleHttpMessageNotReadable( 207 (HttpMessageNotReadableException) ex, request, response, handler); 208 } 209 else if (ex instanceof HttpMessageNotWritableException) { 210 return handleHttpMessageNotWritable( 211 (HttpMessageNotWritableException) ex, request, response, handler); 212 } 213 else if (ex instanceof MethodArgumentNotValidException) { 214 return handleMethodArgumentNotValidException( 215 (MethodArgumentNotValidException) ex, request, response, handler); 216 } 217 else if (ex instanceof MissingServletRequestPartException) { 218 return handleMissingServletRequestPartException( 219 (MissingServletRequestPartException) ex, request, response, handler); 220 } 221 else if (ex instanceof BindException) { 222 return handleBindException((BindException) ex, request, response, handler); 223 } 224 else if (ex instanceof NoHandlerFoundException) { 225 return handleNoHandlerFoundException( 226 (NoHandlerFoundException) ex, request, response, handler); 227 } 228 else if (ex instanceof AsyncRequestTimeoutException) { 229 return handleAsyncRequestTimeoutException( 230 (AsyncRequestTimeoutException) ex, request, response, handler); 231 } 232 } 233 catch (Exception handlerEx) { 234 if (logger.isWarnEnabled()) { 235 logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx); 236 } 237 } 238 return null; 239 } 240 241 /** 242 * Handle the case where no request handler method was found for the particular HTTP request method. 243 * <p>The default implementation logs a warning, sends an HTTP 405 error, sets the "Allow" header, 244 * and returns an empty {@code ModelAndView}. Alternatively, a fallback view could be chosen, 245 * or the HttpRequestMethodNotSupportedException could be rethrown as-is. 246 * @param ex the HttpRequestMethodNotSupportedException to be handled 247 * @param request current HTTP request 248 * @param response current HTTP response 249 * @param handler the executed handler, or {@code null} if none chosen 250 * at the time of the exception (for example, if multipart resolution failed) 251 * @return an empty ModelAndView indicating the exception was handled 252 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 253 */ 254 protected ModelAndView handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, 255 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 256 257 String[] supportedMethods = ex.getSupportedMethods(); 258 if (supportedMethods != null) { 259 response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", ")); 260 } 261 response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage()); 262 return new ModelAndView(); 263 } 264 265 /** 266 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters} 267 * were found for the PUT or POSTed content. 268 * <p>The default implementation sends an HTTP 415 error, sets the "Accept" header, 269 * and returns an empty {@code ModelAndView}. Alternatively, a fallback view could 270 * be chosen, or the HttpMediaTypeNotSupportedException could be rethrown as-is. 271 * @param ex the HttpMediaTypeNotSupportedException to be handled 272 * @param request current HTTP request 273 * @param response current HTTP response 274 * @param handler the executed handler 275 * @return an empty ModelAndView indicating the exception was handled 276 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 277 */ 278 protected ModelAndView handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, 279 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 280 281 response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); 282 List<MediaType> mediaTypes = ex.getSupportedMediaTypes(); 283 if (!CollectionUtils.isEmpty(mediaTypes)) { 284 response.setHeader("Accept", MediaType.toString(mediaTypes)); 285 } 286 return new ModelAndView(); 287 } 288 289 /** 290 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters} 291 * were found that were acceptable for the client (expressed via the {@code Accept} header. 292 * <p>The default implementation sends an HTTP 406 error and returns an empty {@code ModelAndView}. 293 * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotAcceptableException 294 * could be rethrown as-is. 295 * @param ex the HttpMediaTypeNotAcceptableException to be handled 296 * @param request current HTTP request 297 * @param response current HTTP response 298 * @param handler the executed handler 299 * @return an empty ModelAndView indicating the exception was handled 300 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 301 */ 302 protected ModelAndView handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, 303 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 304 305 response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE); 306 return new ModelAndView(); 307 } 308 309 /** 310 * Handle the case when a declared path variable does not match any extracted URI variable. 311 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}. 312 * Alternatively, a fallback view could be chosen, or the MissingPathVariableException 313 * could be rethrown as-is. 314 * @param ex the MissingPathVariableException to be handled 315 * @param request current HTTP request 316 * @param response current HTTP response 317 * @param handler the executed handler 318 * @return an empty ModelAndView indicating the exception was handled 319 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 320 * @since 4.2 321 */ 322 protected ModelAndView handleMissingPathVariable(MissingPathVariableException ex, 323 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 324 325 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage()); 326 return new ModelAndView(); 327 } 328 329 /** 330 * Handle the case when a required parameter is missing. 331 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}. 332 * Alternatively, a fallback view could be chosen, or the MissingServletRequestParameterException 333 * could be rethrown as-is. 334 * @param ex the MissingServletRequestParameterException to be handled 335 * @param request current HTTP request 336 * @param response current HTTP response 337 * @param handler the executed handler 338 * @return an empty ModelAndView indicating the exception was handled 339 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 340 */ 341 protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex, 342 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 343 344 response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); 345 return new ModelAndView(); 346 } 347 348 /** 349 * Handle the case when an unrecoverable binding exception occurs - e.g. required header, required cookie. 350 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}. 351 * Alternatively, a fallback view could be chosen, or the exception could be rethrown as-is. 352 * @param ex the exception to be handled 353 * @param request current HTTP request 354 * @param response current HTTP response 355 * @param handler the executed handler 356 * @return an empty ModelAndView indicating the exception was handled 357 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 358 */ 359 protected ModelAndView handleServletRequestBindingException(ServletRequestBindingException ex, 360 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 361 362 response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); 363 return new ModelAndView(); 364 } 365 366 /** 367 * Handle the case when a {@link org.springframework.web.bind.WebDataBinder} conversion cannot occur. 368 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}. 369 * Alternatively, a fallback view could be chosen, or the ConversionNotSupportedException could be 370 * rethrown as-is. 371 * @param ex the ConversionNotSupportedException to be handled 372 * @param request current HTTP request 373 * @param response current HTTP response 374 * @param handler the executed handler 375 * @return an empty ModelAndView indicating the exception was handled 376 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 377 */ 378 protected ModelAndView handleConversionNotSupported(ConversionNotSupportedException ex, 379 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 380 381 sendServerError(ex, request, response); 382 return new ModelAndView(); 383 } 384 385 /** 386 * Handle the case when a {@link org.springframework.web.bind.WebDataBinder} conversion error occurs. 387 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}. 388 * Alternatively, a fallback view could be chosen, or the TypeMismatchException could be rethrown as-is. 389 * @param ex the TypeMismatchException to be handled 390 * @param request current HTTP request 391 * @param response current HTTP response 392 * @param handler the executed handler 393 * @return an empty ModelAndView indicating the exception was handled 394 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 395 */ 396 protected ModelAndView handleTypeMismatch(TypeMismatchException ex, 397 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 398 399 response.sendError(HttpServletResponse.SC_BAD_REQUEST); 400 return new ModelAndView(); 401 } 402 403 /** 404 * Handle the case where a {@linkplain org.springframework.http.converter.HttpMessageConverter message converter} 405 * cannot read from an HTTP request. 406 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}. 407 * Alternatively, a fallback view could be chosen, or the HttpMessageNotReadableException could be 408 * rethrown as-is. 409 * @param ex the HttpMessageNotReadableException to be handled 410 * @param request current HTTP request 411 * @param response current HTTP response 412 * @param handler the executed handler 413 * @return an empty ModelAndView indicating the exception was handled 414 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 415 */ 416 protected ModelAndView handleHttpMessageNotReadable(HttpMessageNotReadableException ex, 417 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 418 419 response.sendError(HttpServletResponse.SC_BAD_REQUEST); 420 return new ModelAndView(); 421 } 422 423 /** 424 * Handle the case where a 425 * {@linkplain org.springframework.http.converter.HttpMessageConverter message converter} 426 * cannot write to an HTTP request. 427 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}. 428 * Alternatively, a fallback view could be chosen, or the HttpMessageNotWritableException could 429 * be rethrown as-is. 430 * @param ex the HttpMessageNotWritableException to be handled 431 * @param request current HTTP request 432 * @param response current HTTP response 433 * @param handler the executed handler 434 * @return an empty ModelAndView indicating the exception was handled 435 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 436 */ 437 protected ModelAndView handleHttpMessageNotWritable(HttpMessageNotWritableException ex, 438 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 439 440 sendServerError(ex, request, response); 441 return new ModelAndView(); 442 } 443 444 /** 445 * Handle the case where an argument annotated with {@code @Valid} such as 446 * an {@link RequestBody} or {@link RequestPart} argument fails validation. 447 * <p>By default, an HTTP 400 error is sent back to the client. 448 * @param request current HTTP request 449 * @param response current HTTP response 450 * @param handler the executed handler 451 * @return an empty ModelAndView indicating the exception was handled 452 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 453 */ 454 protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, 455 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 456 457 response.sendError(HttpServletResponse.SC_BAD_REQUEST); 458 return new ModelAndView(); 459 } 460 461 /** 462 * Handle the case where an {@linkplain RequestPart @RequestPart}, a {@link MultipartFile}, 463 * or a {@code javax.servlet.http.Part} argument is required but is missing. 464 * <p>By default, an HTTP 400 error is sent back to the client. 465 * @param request current HTTP request 466 * @param response current HTTP response 467 * @param handler the executed handler 468 * @return an empty ModelAndView indicating the exception was handled 469 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 470 */ 471 protected ModelAndView handleMissingServletRequestPartException(MissingServletRequestPartException ex, 472 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 473 474 response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); 475 return new ModelAndView(); 476 } 477 478 /** 479 * Handle the case where an {@linkplain ModelAttribute @ModelAttribute} method 480 * argument has binding or validation errors and is not followed by another 481 * method argument of type {@link BindingResult}. 482 * <p>By default, an HTTP 400 error is sent back to the client. 483 * @param request current HTTP request 484 * @param response current HTTP response 485 * @param handler the executed handler 486 * @return an empty ModelAndView indicating the exception was handled 487 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 488 */ 489 protected ModelAndView handleBindException(BindException ex, HttpServletRequest request, 490 HttpServletResponse response, @Nullable Object handler) throws IOException { 491 492 response.sendError(HttpServletResponse.SC_BAD_REQUEST); 493 return new ModelAndView(); 494 } 495 496 /** 497 * Handle the case where no handler was found during the dispatch. 498 * <p>The default implementation sends an HTTP 404 error and returns an empty 499 * {@code ModelAndView}. Alternatively, a fallback view could be chosen, 500 * or the NoHandlerFoundException could be rethrown as-is. 501 * @param ex the NoHandlerFoundException to be handled 502 * @param request current HTTP request 503 * @param response current HTTP response 504 * @param handler the executed handler, or {@code null} if none chosen 505 * at the time of the exception (for example, if multipart resolution failed) 506 * @return an empty ModelAndView indicating the exception was handled 507 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 508 * @since 4.0 509 */ 510 protected ModelAndView handleNoHandlerFoundException(NoHandlerFoundException ex, 511 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 512 513 pageNotFoundLogger.warn(ex.getMessage()); 514 response.sendError(HttpServletResponse.SC_NOT_FOUND); 515 return new ModelAndView(); 516 } 517 518 /** 519 * Handle the case where an async request timed out. 520 * <p>The default implementation sends an HTTP 503 error. 521 * @param ex the {@link AsyncRequestTimeoutException }to be handled 522 * @param request current HTTP request 523 * @param response current HTTP response 524 * @param handler the executed handler, or {@code null} if none chosen 525 * at the time of the exception (for example, if multipart resolution failed) 526 * @return an empty ModelAndView indicating the exception was handled 527 * @throws IOException potentially thrown from {@link HttpServletResponse#sendError} 528 * @since 4.2.8 529 */ 530 protected ModelAndView handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, 531 HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 532 533 if (!response.isCommitted()) { 534 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); 535 } 536 else { 537 logger.warn("Async request timed out"); 538 } 539 return new ModelAndView(); 540 } 541 542 /** 543 * Invoked to send a server error. Sets the status to 500 and also sets the 544 * request attribute "javax.servlet.error.exception" to the Exception. 545 */ 546 protected void sendServerError(Exception ex, HttpServletRequest request, HttpServletResponse response) 547 throws IOException { 548 549 request.setAttribute("javax.servlet.error.exception", ex); 550 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 551 } 552 553}