DefaultHandlerExceptionResolver.java 24.1 KB
Newer Older
1
/*
2
 * Copyright 2002-2018 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
package org.springframework.web.servlet.mvc.support;
18

19
import java.io.IOException;
20 21 22 23 24 25
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
26

27
import org.springframework.beans.ConversionNotSupportedException;
28 29 30 31 32
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.Ordered;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
33
import org.springframework.lang.Nullable;
34
import org.springframework.util.CollectionUtils;
35
import org.springframework.util.StringUtils;
36 37
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
J
Juergen Hoeller 已提交
38
import org.springframework.web.HttpMediaTypeNotAcceptableException;
39 40
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
41
import org.springframework.web.bind.MethodArgumentNotValidException;
42
import org.springframework.web.bind.MissingPathVariableException;
43
import org.springframework.web.bind.MissingServletRequestParameterException;
44
import org.springframework.web.bind.ServletRequestBindingException;
45
import org.springframework.web.bind.annotation.ModelAttribute;
46 47
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
48
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
49 50
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
51
import org.springframework.web.servlet.ModelAndView;
52
import org.springframework.web.servlet.NoHandlerFoundException;
53
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
54 55

/**
56 57 58
 * The default implementation of the {@link org.springframework.web.servlet.HandlerExceptionResolver}
 * interface, resolving standard Spring MVC exceptions and translating them to corresponding
 * HTTP status codes.
J
Juergen Hoeller 已提交
59
 *
60 61
 * <p>This exception resolver is enabled by default in the common Spring
 * {@link org.springframework.web.servlet.DispatcherServlet}.
62
 *
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
 * <p>
 * <table>
 * <caption>Supported Exceptions</caption>
 * <thead>
 * <tr>
 * <th class="colFirst">Exception</th>
 * <th class="colLast">HTTP Status Code</th>
 * </tr>
 * </thead>
 * <tbody>
 * <tr class="altColor">
 * <td><p>HttpRequestMethodNotSupportedException</p></td>
 * <td><p>405 (SC_METHOD_NOT_ALLOWED)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>HttpMediaTypeNotSupportedException</p></td>
 * <td><p>415 (SC_UNSUPPORTED_MEDIA_TYPE)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>HttpMediaTypeNotAcceptableException</p></td>
 * <td><p>406 (SC_NOT_ACCEPTABLE)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>MissingPathVariableException</p></td>
 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>MissingServletRequestParameterException</p></td>
 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>ServletRequestBindingException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>ConversionNotSupportedException</p></td>
 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>TypeMismatchException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>HttpMessageNotReadableException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>HttpMessageNotWritableException</p></td>
 * <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>MethodArgumentNotValidException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>MissingServletRequestPartException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>BindException</p></td>
 * <td><p>400 (SC_BAD_REQUEST)</p></td>
 * </tr>
 * <tr class="rowColor">
 * <td><p>NoHandlerFoundException</p></td>
 * <td><p>400 (SC_NOT_FOUND)</p></td>
 * </tr>
 * <tr class="altColor">
 * <td><p>AsyncRequestTimeoutException</p></td>
 * <td><p>503 (SC_SERVICE_UNAVAILABLE)</p></td>
 * </tr>
 * </tbody>
 * </table>
 *
136
 * @author Arjen Poutsma
137
 * @author Rossen Stoyanchev
138
 * @author Juergen Hoeller
J
Juergen Hoeller 已提交
139
 * @since 3.0
140
 * @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
 */
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {

	/**
	 * Log category to use when no mapped handler is found for a request.
	 * @see #pageNotFoundLogger
	 */
	public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";

	/**
	 * Additional logger to use when no mapped handler is found for a request.
	 * @see #PAGE_NOT_FOUND_LOG_CATEGORY
	 */
	protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);

J
Juergen Hoeller 已提交
156 157 158 159

	/**
	 * Sets the {@linkplain #setOrder(int) order} to {@link #LOWEST_PRECEDENCE}.
	 */
160 161 162 163
	public DefaultHandlerExceptionResolver() {
		setOrder(Ordered.LOWEST_PRECEDENCE);
	}

J
Juergen Hoeller 已提交
164

165
	@Override
166
	@Nullable
J
Juergen Hoeller 已提交
167 168
	protected ModelAndView doResolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
J
Juergen Hoeller 已提交
169

170
		try {
171
			if (ex instanceof HttpRequestMethodNotSupportedException) {
172 173
				return handleHttpRequestMethodNotSupported(
						(HttpRequestMethodNotSupportedException) ex, request, response, handler);
174 175
			}
			else if (ex instanceof HttpMediaTypeNotSupportedException) {
176 177
				return handleHttpMediaTypeNotSupported(
						(HttpMediaTypeNotSupportedException) ex, request, response, handler);
178
			}
179
			else if (ex instanceof HttpMediaTypeNotAcceptableException) {
180 181
				return handleHttpMediaTypeNotAcceptable(
						(HttpMediaTypeNotAcceptableException) ex, request, response, handler);
182
			}
183
			else if (ex instanceof MissingPathVariableException) {
184 185
				return handleMissingPathVariable(
						(MissingPathVariableException) ex, request, response, handler);
186
			}
187
			else if (ex instanceof MissingServletRequestParameterException) {
188 189
				return handleMissingServletRequestParameter(
						(MissingServletRequestParameterException) ex, request, response, handler);
190
			}
191
			else if (ex instanceof ServletRequestBindingException) {
192 193
				return handleServletRequestBindingException(
						(ServletRequestBindingException) ex, request, response, handler);
194
			}
195
			else if (ex instanceof ConversionNotSupportedException) {
196 197
				return handleConversionNotSupported(
						(ConversionNotSupportedException) ex, request, response, handler);
198
			}
199
			else if (ex instanceof TypeMismatchException) {
200 201
				return handleTypeMismatch(
						(TypeMismatchException) ex, request, response, handler);
202 203
			}
			else if (ex instanceof HttpMessageNotReadableException) {
204 205
				return handleHttpMessageNotReadable(
						(HttpMessageNotReadableException) ex, request, response, handler);
206 207
			}
			else if (ex instanceof HttpMessageNotWritableException) {
208 209
				return handleHttpMessageNotWritable(
						(HttpMessageNotWritableException) ex, request, response, handler);
210
			}
211
			else if (ex instanceof MethodArgumentNotValidException) {
212 213
				return handleMethodArgumentNotValidException(
						(MethodArgumentNotValidException) ex, request, response, handler);
214
			}
215
			else if (ex instanceof MissingServletRequestPartException) {
216 217
				return handleMissingServletRequestPartException(
						(MissingServletRequestPartException) ex, request, response, handler);
218
			}
219 220 221
			else if (ex instanceof BindException) {
				return handleBindException((BindException) ex, request, response, handler);
			}
222
			else if (ex instanceof NoHandlerFoundException) {
223 224
				return handleNoHandlerFoundException(
						(NoHandlerFoundException) ex, request, response, handler);
225
			}
226 227 228 229
			else if (ex instanceof AsyncRequestTimeoutException) {
				return handleAsyncRequestTimeoutException(
						(AsyncRequestTimeoutException) ex, request, response, handler);
			}
230 231
			else {
				return null;
232
			}
233 234 235 236 237

		}
		catch (Exception handlerEx) {
			logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx);
			return null;
238 239 240 241
		}
	}

	/**
J
Juergen Hoeller 已提交
242 243 244 245
	 * Handle the case where no request handler method was found for the particular HTTP request method.
	 * <p>The default implementation logs a warning, sends an HTTP 405 error, sets the "Allow" header,
	 * and returns an empty {@code ModelAndView}. Alternatively, a fallback view could be chosen,
	 * or the HttpRequestMethodNotSupportedException could be rethrown as-is.
246 247 248
	 * @param ex the HttpRequestMethodNotSupportedException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
249
	 * @param handler the executed handler, or {@code null} if none chosen
J
Juergen Hoeller 已提交
250
	 * at the time of the exception (for example, if multipart resolution failed)
251 252
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
253 254
	 */
	protected ModelAndView handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
255
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
256 257 258 259 260 261 262 263 264 265 266 267

		pageNotFoundLogger.warn(ex.getMessage());
		String[] supportedMethods = ex.getSupportedMethods();
		if (supportedMethods != null) {
			response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
		}
		response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage());
		return new ModelAndView();
	}

	/**
	 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters}
268 269 270 271
	 * were found for the PUT or POSTed content.
	 * <p>The default implementation sends an HTTP 415 error, sets the "Accept" header,
	 * and returns an empty {@code ModelAndView}. Alternatively, a fallback view could
	 * be chosen, or the HttpMediaTypeNotSupportedException could be rethrown as-is.
272 273 274
	 * @param ex the HttpMediaTypeNotSupportedException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
275 276 277
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
278 279
	 */
	protected ModelAndView handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex,
280
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
281 282 283

		response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
		List<MediaType> mediaTypes = ex.getSupportedMediaTypes();
284
		if (!CollectionUtils.isEmpty(mediaTypes)) {
285 286 287 288 289
			response.setHeader("Accept", MediaType.toString(mediaTypes));
		}
		return new ModelAndView();
	}

290 291 292
	/**
	 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters}
	 * were found that were acceptable for the client (expressed via the {@code Accept} header.
J
Juergen Hoeller 已提交
293 294 295
	 * <p>The default implementation sends an HTTP 406 error and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotAcceptableException
	 * could be rethrown as-is.
296 297 298
	 * @param ex the HttpMediaTypeNotAcceptableException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
299 300 301
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
302 303
	 */
	protected ModelAndView handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex,
304
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
305 306 307 308 309

		response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
		return new ModelAndView();
	}

310 311 312 313 314 315 316 317 318 319 320 321 322 323
	/**
	 * Handle the case when a declared path variable does not match any extracted URI variable.
	 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the MissingPathVariableException
	 * could be rethrown as-is.
	 * @param ex the MissingPathVariableException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 * @since 4.2
	 */
	protected ModelAndView handleMissingPathVariable(MissingPathVariableException ex,
324
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
325 326 327 328 329

		response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
		return new ModelAndView();
	}

330
	/**
J
Juergen Hoeller 已提交
331 332 333 334
	 * Handle the case when a required parameter is missing.
	 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the MissingServletRequestParameterException
	 * could be rethrown as-is.
335 336 337
	 * @param ex the MissingServletRequestParameterException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
338 339 340
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
341 342
	 */
	protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
343
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
344

345
		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
		return new ModelAndView();
	}

	/**
	 * Handle the case when an unrecoverable binding exception occurs - e.g. required header, required cookie.
	 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the exception could be rethrown as-is.
	 * @param ex the exception to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 */
	protected ModelAndView handleServletRequestBindingException(ServletRequestBindingException ex,
361
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
362

363
		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
364 365 366
		return new ModelAndView();
	}

367
	/**
J
Juergen Hoeller 已提交
368 369 370
	 * Handle the case when a {@link org.springframework.web.bind.WebDataBinder} conversion cannot occur.
	 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the TypeMismatchException could be rethrown as-is.
371 372 373
	 * @param ex the ConversionNotSupportedException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
374 375 376
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
377 378
	 */
	protected ModelAndView handleConversionNotSupported(ConversionNotSupportedException ex,
379
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
J
Juergen Hoeller 已提交
380

381 382 383
		if (logger.isWarnEnabled()) {
			logger.warn("Failed to convert request element: " + ex);
		}
384
		sendServerError(ex, request, response);
385 386 387
		return new ModelAndView();
	}

388
	/**
J
Juergen Hoeller 已提交
389 390 391
	 * Handle the case when a {@link org.springframework.web.bind.WebDataBinder} conversion error occurs.
	 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the TypeMismatchException could be rethrown as-is.
392 393 394
	 * @param ex the TypeMismatchException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
395 396 397
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
398 399
	 */
	protected ModelAndView handleTypeMismatch(TypeMismatchException ex,
400
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
J
Juergen Hoeller 已提交
401

402 403 404
		if (logger.isWarnEnabled()) {
			logger.warn("Failed to bind request element: " + ex);
		}
405 406 407 408 409
		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
		return new ModelAndView();
	}

	/**
J
Juergen Hoeller 已提交
410 411 412 413
	 * Handle the case where a {@linkplain org.springframework.http.converter.HttpMessageConverter message converter}
	 * cannot read from a HTTP request.
	 * <p>The default implementation sends an HTTP 400 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException could be
414 415 416 417
	 * rethrown as-is.
	 * @param ex the HttpMessageNotReadableException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
418 419 420
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
421 422
	 */
	protected ModelAndView handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
423
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
424

425 426 427
		if (logger.isWarnEnabled()) {
			logger.warn("Failed to read HTTP message: " + ex);
		}
428
		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
429 430 431 432
		return new ModelAndView();
	}

	/**
J
Juergen Hoeller 已提交
433 434 435 436
	 * Handle the case where a {@linkplain org.springframework.http.converter.HttpMessageConverter message converter}
	 * cannot write to a HTTP request.
	 * <p>The default implementation sends an HTTP 500 error, and returns an empty {@code ModelAndView}.
	 * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException could be
437 438 439 440
	 * rethrown as-is.
	 * @param ex the HttpMessageNotWritableException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
441 442 443
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
444 445
	 */
	protected ModelAndView handleHttpMessageNotWritable(HttpMessageNotWritableException ex,
446
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
447

448 449 450
		if (logger.isWarnEnabled()) {
			logger.warn("Failed to write HTTP message: " + ex);
		}
451
		sendServerError(ex, request, response);
452 453 454
		return new ModelAndView();
	}

455
	/**
456 457
	 * Handle the case where an argument annotated with {@code @Valid} such as
	 * an {@link RequestBody} or {@link RequestPart} argument fails validation.
458
	 * An HTTP 400 error is sent back to the client.
459 460
	 * @param request current HTTP request
	 * @param response current HTTP response
461 462 463
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
464
	 */
465
	protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotValidException ex,
466
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
467

468
 		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
469 470 471
		return new ModelAndView();
	}

472
	/**
473 474
	 * Handle the case where an {@linkplain RequestPart @RequestPart}, a {@link MultipartFile},
	 * or a {@code javax.servlet.http.Part} argument is required but is missing.
475 476 477 478 479 480 481 482
	 * An HTTP 400 error is sent back to the client.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 */
	protected ModelAndView handleMissingServletRequestPartException(MissingServletRequestPartException ex,
483
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
484

485
		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
486 487 488
		return new ModelAndView();
	}

489 490 491 492
	/**
	 * Handle the case where an {@linkplain ModelAttribute @ModelAttribute} method
	 * argument has binding or validation errors and is not followed by another
	 * method argument of type {@link BindingResult}.
493
	 * By default, an HTTP 400 error is sent back to the client.
494 495 496 497 498 499 500
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 */
	protected ModelAndView handleBindException(BindException ex, HttpServletRequest request,
501
			HttpServletResponse response, @Nullable Object handler) throws IOException {
502

503 504 505 506
		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
		return new ModelAndView();
	}

507 508
	/**
	 * Handle the case where no handler was found during the dispatch.
509 510
	 * <p>The default implementation sends an HTTP 404 error and returns an empty
	 * {@code ModelAndView}. Alternatively, a fallback view could be chosen,
511 512 513 514 515 516 517 518 519 520
	 * or the NoHandlerFoundException could be rethrown as-is.
	 * @param ex the NoHandlerFoundException to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler, or {@code null} if none chosen
	 * at the time of the exception (for example, if multipart resolution failed)
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 * @since 4.0
	 */
521
	protected ModelAndView handleNoHandlerFoundException(NoHandlerFoundException ex,
522
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
523

524 525 526 527
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		return new ModelAndView();
	}

528 529 530 531 532 533 534 535 536 537 538 539 540
	/**
	 * Handle the case where an async request timed out.
	 * <p>The default implementation sends an HTTP 503 error.
	 * @param ex the {@link AsyncRequestTimeoutException }to be handled
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler the executed handler, or {@code null} if none chosen
	 * at the time of the exception (for example, if multipart resolution failed)
	 * @return an empty ModelAndView indicating the exception was handled
	 * @throws IOException potentially thrown from response.sendError()
	 * @since 4.2.8
	 */
	protected ModelAndView handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex,
541
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
542

543 544 545
		if (!response.isCommitted()) {
			response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
		}
546 547
		else if (logger.isWarnEnabled()) {
			logger.warn("Async request timed out");
548
		}
549 550 551
		return new ModelAndView();
	}

552 553 554 555 556 557 558 559 560 561 562
	/**
	 * Invoked to send a server error. Sets the status to 500 and also sets the
	 * request attribute "javax.servlet.error.exception" to the Exception.
	 */
	protected void sendServerError(Exception ex, HttpServletRequest request, HttpServletResponse response)
			throws IOException {

		request.setAttribute("javax.servlet.error.exception", ex);
		response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
	}

563
}