Skip to content

Commit 10e3d3b

Browse files
committed
Merge branch '6.1.x'
2 parents 2c9ed46 + d03ea0b commit 10e3d3b

File tree

8 files changed

+59
-77
lines changed

8 files changed

+59
-77
lines changed

framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[[spring-mvc-test-vs-end-to-end-integration-tests]]
22
= MockMvc vs End-to-End Tests
33

4-
MockMVc is built on Servlet API mock implementations from the
4+
MockMvc is built on Servlet API mock implementations from the
55
`spring-test` module and does not rely on a running container. Therefore, there are
66
some differences when compared to full end-to-end integration tests with an actual
77
client and a live server running.
Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,16 @@
11
[[spring-mvc-test-vs-streaming-response]]
22
= Streaming Responses
33

4-
The best way to test streaming responses such as Server-Sent Events is through the
5-
<<WebTestClient>> which can be used as a test client to connect to a `MockMvc` instance
6-
to perform tests on Spring MVC controllers without a running server. For example:
7-
8-
[tabs]
9-
======
10-
Java::
11-
+
12-
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
13-
----
14-
WebTestClient client = MockMvcWebTestClient.bindToController(new SseController()).build();
15-
16-
FluxExchangeResult<Person> exchangeResult = client.get()
17-
.uri("/persons")
18-
.exchange()
19-
.expectStatus().isOk()
20-
.expectHeader().contentType("text/event-stream")
21-
.returnResult(Person.class);
22-
23-
// Use StepVerifier from Project Reactor to test the streaming response
24-
25-
StepVerifier.create(exchangeResult.getResponseBody())
26-
.expectNext(new Person("N0"), new Person("N1"), new Person("N2"))
27-
.expectNextCount(4)
28-
.consumeNextWith(person -> assertThat(person.getName()).endsWith("7"))
29-
.thenCancel()
30-
.verify();
31-
----
32-
======
33-
34-
`WebTestClient` can also connect to a live server and perform full end-to-end integration
35-
tests. This is also supported in Spring Boot where you can
36-
{spring-boot-docs}/spring-boot-features.html#boot-features-testing-spring-boot-applications-testing-with-running-server[test a running server].
4+
You can use `WebTestClient` to test xref:testing/webtestclient.adoc#webtestclient-stream[streaming responses]
5+
such as Server-Sent Events. However, `MockMvcWebTestClient` doesn't support infinite
6+
streams because there is no way to cancel the server stream from the client side.
7+
To test infinite streams, you'll need to
8+
xref:testing/webtestclient.adoc#webtestclient-server-config[bind to] a running server,
9+
or when using Spring Boot,
10+
{spring-boot-docs}/spring-boot-features.html#boot-features-testing-spring-boot-applications-testing-with-running-server[test with a running server].
11+
12+
`MockMvcWebTestClient` does support asynchronous responses, and even streaming responses.
13+
The limitation is that it can't influence the server to stop, and therefore the server
14+
must finish writing the response on its own.
3715

3816

framework-docs/modules/ROOT/pages/web/webmvc/mvc-config/interceptors.adoc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@ You can register interceptors to apply to incoming requests, as the following ex
55

66
include-code::./WebConfiguration[tag=snippet,indent=0]
77

8-
NOTE: Interceptors are not ideally suited as a security layer due to the potential
9-
for a mismatch with annotated controller path matching, which can also match trailing
10-
slashes and path extensions transparently, along with other path matching options. Many
11-
of these options have been deprecated but the potential for a mismatch remains.
12-
Generally, we recommend using Spring Security which includes a dedicated
13-
https://docs.spring.io/spring-security/reference/servlet/integrations/mvc.html#mvc-requestmatcher[MvcRequestMatcher]
14-
to align with Spring MVC path matching and also has a security firewall that blocks many
15-
unwanted characters in URL paths.
8+
WARNING: Interceptors are not ideally suited as a security layer due to the potential for
9+
a mismatch with annotated controller path matching. Generally, we recommend using Spring
10+
Security, or alternatively a similar approach integrated with the Servlet filter chain,
11+
and applied as early as possible.
1612

1713
NOTE: The XML config declares interceptors as `MappedInterceptor` beans, and those are in
1814
turn detected by any `HandlerMapping` bean, including those from other frameworks.
Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
[[mvc-handlermapping-interceptor]]
22
= Interception
33

4-
All `HandlerMapping` implementations support handler interceptors that are useful when
5-
you want to apply specific functionality to certain requests -- for example, checking for
6-
a principal. Interceptors must implement `HandlerInterceptor` from the
7-
`org.springframework.web.servlet` package with three methods that should provide enough
8-
flexibility to do all kinds of pre-processing and post-processing:
9-
10-
* `preHandle(..)`: Before the actual handler is run
11-
* `postHandle(..)`: After the handler is run
12-
* `afterCompletion(..)`: After the complete request has finished
13-
14-
The `preHandle(..)` method returns a boolean value. You can use this method to break or
15-
continue the processing of the execution chain. When this method returns `true`, the
16-
handler execution chain continues. When it returns false, the `DispatcherServlet`
17-
assumes the interceptor itself has taken care of requests (and, for example, rendered an
18-
appropriate view) and does not continue executing the other interceptors and the actual
19-
handler in the execution chain.
4+
All `HandlerMapping` implementations support handler interception which is useful when
5+
you want to apply functionality across requests. A `HandlerInterceptor` can implement the
6+
following:
7+
8+
* `preHandle(..)` -- callback before the actual handler is run that returns a boolean.
9+
If the method returns `true`, execution continues; if it returns `false`, the rest of the
10+
execution chain is bypassed and the handler is not called.
11+
* `postHandle(..)` -- callback after the handler is run.
12+
* `afterCompletion(..)` -- callback after the complete request has finished.
13+
14+
NOTE: For `@ResponseBody` and `ResponseEntity` controller methods, the response is written
15+
and committed within the `HandlerAdapter`, before `postHandle` is called. That means it is
16+
too late to change the response, such as to add an extra header. You can implement
17+
`ResponseBodyAdvice` and declare it as an
18+
xref:web/webmvc/mvc-controller/ann-advice.adoc[Controller Advice] bean or configure it
19+
directly on `RequestMappingHandlerAdapter`.
2020

2121
See xref:web/webmvc/mvc-config/interceptors.adoc[Interceptors] in the section on MVC configuration for examples of how to
2222
configure interceptors. You can also register them directly by using setters on individual
2323
`HandlerMapping` implementations.
2424

25-
`postHandle` method is less useful with `@ResponseBody` and `ResponseEntity` methods for
26-
which the response is written and committed within the `HandlerAdapter` and before
27-
`postHandle`. That means it is too late to make any changes to the response, such as adding
28-
an extra header. For such scenarios, you can implement `ResponseBodyAdvice` and either
29-
declare it as an xref:web/webmvc/mvc-controller/ann-advice.adoc[Controller Advice] bean or configure it directly on
30-
`RequestMappingHandlerAdapter`.
31-
32-
33-
25+
WARNING: Interceptors are not ideally suited as a security layer due to the potential for
26+
a mismatch with annotated controller path matching. Generally, we recommend using Spring
27+
Security, or alternatively a similar approach integrated with the Servlet filter chain,
28+
and applied as early as possible.
3429

spring-web/src/main/java/org/springframework/web/ErrorResponse.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ default HttpHeaders getHeaders() {
6161
* Return the body for the response, formatted as an RFC 9457
6262
* {@link ProblemDetail} whose {@link ProblemDetail#getStatus() status}
6363
* should match the response status.
64+
* <p><strong>Note:</strong> The returned {@code ProblemDetail} may be
65+
* updated before the response is rendered, e.g. via
66+
* {@link #updateAndGetBody(MessageSource, Locale)}. Therefore, implementing
67+
* methods should use an instance field, and should not re-create the
68+
* {@code ProblemDetail} on every call, nor use a static variable.
6469
*/
6570
ProblemDetail getBody();
6671

spring-web/src/main/java/org/springframework/web/context/request/async/AsyncRequestTimeoutException.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,14 +37,17 @@
3737
@SuppressWarnings("serial")
3838
public class AsyncRequestTimeoutException extends RuntimeException implements ErrorResponse {
3939

40+
private final ProblemDetail body = ProblemDetail.forStatus(getStatusCode());
41+
42+
4043
@Override
4144
public HttpStatusCode getStatusCode() {
4245
return HttpStatus.SERVICE_UNAVAILABLE;
4346
}
4447

4548
@Override
4649
public ProblemDetail getBody() {
47-
return ProblemDetail.forStatus(getStatusCode());
50+
return this.body;
4851
}
4952

5053
}

spring-web/src/main/java/org/springframework/web/multipart/MaxUploadSizeExceededException.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,10 +33,9 @@
3333
@SuppressWarnings("serial")
3434
public class MaxUploadSizeExceededException extends MultipartException implements ErrorResponse {
3535

36-
private static final ProblemDetail body =
36+
private final ProblemDetail body =
3737
ProblemDetail.forStatusAndDetail(HttpStatus.PAYLOAD_TOO_LARGE, "Maximum upload size exceeded");
3838

39-
4039
private final long maxUploadSize;
4140

4241

@@ -76,7 +75,7 @@ public HttpStatusCode getStatusCode() {
7675

7776
@Override
7877
public ProblemDetail getBody() {
79-
return body;
78+
return this.body;
8079
}
8180

8281
}

spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerInterceptor.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,9 +30,9 @@
3030
*
3131
* <p>A HandlerInterceptor gets called before the appropriate HandlerAdapter
3232
* triggers the execution of the handler itself. This mechanism can be used
33-
* for a large field of preprocessing aspects, e.g. for authorization checks,
34-
* or common handler behavior like locale or theme changes. Its main purpose
35-
* is to allow for factoring out repetitive handler code.
33+
* for a large field of preprocessing aspects, or common handler behavior
34+
* like locale or theme changes. Its main purpose is to allow for factoring
35+
* out repetitive handler code.
3636
*
3737
* <p>In an asynchronous processing scenario, the handler may be executed in a
3838
* separate thread while the main thread exits without rendering or invoking the
@@ -63,6 +63,12 @@
6363
* forms and GZIP compression. This typically shows when one needs to map the
6464
* filter to certain content types (e.g. images), or to all requests.
6565
*
66+
* <p><strong>Note:</strong> Interceptors are not ideally suited as a security
67+
* layer due to the potential for a mismatch with annotated controller path matching.
68+
* Generally, we recommend using Spring Security, or alternatively a similar
69+
* approach integrated with the Servlet filter chain, and applied as early as
70+
* possible.
71+
*
6672
* @author Juergen Hoeller
6773
* @since 20.06.2003
6874
* @see HandlerExecutionChain#getInterceptors

0 commit comments

Comments
 (0)