0
# Reactive Web Support
1
2
Non-blocking web server infrastructure for building reactive applications with WebFlux. Provides the foundation for reactive web programming with streaming data processing and backpressure support.
3
4
## Capabilities
5
6
### Core Reactive Web Interfaces
7
8
Fundamental interfaces for reactive web request/response handling and filtering.
9
10
```java { .api }
11
/**
12
* Contract to handle a web request reactively
13
*/
14
@FunctionalInterface
15
interface WebHandler {
16
/** Handle the web request and return a completion signal */
17
Mono<Void> handle(ServerWebExchange exchange);
18
}
19
20
/**
21
* Contract for HTTP request-response interaction in reactive environment
22
*/
23
interface ServerWebExchange {
24
/** Get the server HTTP request */
25
ServerHttpRequest getRequest();
26
/** Get the server HTTP response */
27
ServerHttpResponse getResponse();
28
29
/** Get exchange attributes */
30
Map<String, Object> getAttributes();
31
/** Get attribute value */
32
@Nullable
33
<T> T getAttribute(String name);
34
/** Get attribute with default value */
35
<T> T getAttributeOrDefault(String name, T defaultValue);
36
/** Get required attribute (throws if not present) */
37
<T> T getRequiredAttribute(String name);
38
39
/** Create a builder for mutating exchange properties */
40
ServerWebExchange.Builder mutate();
41
42
/** Check if response should not be modified based on request conditions */
43
boolean isNotModified();
44
/** Check not modified with last modified date */
45
boolean checkNotModified(Instant lastModified);
46
/** Check not modified with ETag */
47
boolean checkNotModified(String etag);
48
/** Check not modified with both ETag and last modified */
49
boolean checkNotModified(@Nullable String etag, Instant lastModified);
50
51
/** Transform URL (useful for proxies and gateways) */
52
String transformUrl(String url);
53
/** Add URL transformer */
54
void addUrlTransformer(Function<String, String> transformer);
55
56
/** Get authenticated principal */
57
<T extends Principal> Mono<T> getPrincipal();
58
/** Get web session */
59
Mono<WebSession> getSession();
60
/** Get form data */
61
Mono<MultiValueMap<String, String>> getFormData();
62
/** Get multipart data */
63
Mono<MultiValueMap<String, Part>> getMultipartData();
64
65
/** Get locale context */
66
LocaleContext getLocaleContext();
67
/** Get application context */
68
ApplicationContext getApplicationContext();
69
}
70
71
/**
72
* Contract for interception-style processing of web requests
73
*/
74
@FunctionalInterface
75
interface WebFilter {
76
/** Filter the request and delegate to the next filter or handler */
77
Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
78
}
79
80
/**
81
* Contract to allow WebFilter to delegate to the next in chain
82
*/
83
@FunctionalInterface
84
interface WebFilterChain {
85
/** Invoke the next filter in the chain or the handler */
86
Mono<Void> filter(ServerWebExchange exchange);
87
}
88
```
89
90
### Server HTTP Abstractions
91
92
Reactive server-side HTTP request and response abstractions with streaming support.
93
94
```java { .api }
95
/**
96
* Reactive server-side HTTP request
97
*/
98
interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
99
/** Get unique request ID */
100
String getId();
101
/** Get request path */
102
RequestPath getPath();
103
/** Get query parameters */
104
MultiValueMap<String, String> getQueryParams();
105
/** Get cookies */
106
MultiValueMap<String, HttpCookie> getCookies();
107
108
/** Get remote address */
109
@Nullable
110
InetSocketAddress getRemoteAddress();
111
/** Get local address */
112
@Nullable
113
InetSocketAddress getLocalAddress();
114
/** Get SSL info */
115
@Nullable
116
SslInfo getSslInfo();
117
118
/** Create builder for mutating request properties */
119
ServerHttpRequest.Builder mutate();
120
}
121
122
/**
123
* Reactive server-side HTTP response
124
*/
125
interface ServerHttpResponse extends ReactiveHttpOutputMessage {
126
/** Set response status code */
127
boolean setStatusCode(@Nullable HttpStatusCode status);
128
/** Get response status code */
129
@Nullable
130
HttpStatusCode getStatusCode();
131
132
/** Get response cookies */
133
MultiValueMap<String, ResponseCookie> getCookies();
134
/** Add response cookie */
135
void addCookie(ResponseCookie cookie);
136
}
137
138
/**
139
* Represents HTTP request path with segments and parameters
140
*/
141
interface RequestPath extends PathContainer {
142
/** Get full path value */
143
String value();
144
/** Get context path */
145
PathContainer contextPath();
146
/** Get path within application */
147
PathContainer pathWithinApplication();
148
149
/** Modify context path */
150
RequestPath modifyContextPath(String contextPath);
151
}
152
153
/**
154
* HTTP cookie representation
155
*/
156
class HttpCookie {
157
HttpCookie(String name, String value);
158
159
/** Get cookie name */
160
String getName();
161
/** Get cookie value */
162
String getValue();
163
}
164
165
/**
166
* Response cookie with additional attributes
167
*/
168
class ResponseCookie extends HttpCookie {
169
/** Get max age */
170
Duration getMaxAge();
171
/** Get domain */
172
@Nullable
173
String getDomain();
174
/** Get path */
175
@Nullable
176
String getPath();
177
/** Is secure flag set */
178
boolean isSecure();
179
/** Is HTTP only flag set */
180
boolean isHttpOnly();
181
/** Get SameSite attribute */
182
@Nullable
183
String getSameSite();
184
185
/** Create response cookie builder */
186
static ResponseCookieBuilder from(String name, String value);
187
static ResponseCookieBuilder fromClientResponse(String name, String value);
188
}
189
```
190
191
### Web Session Management
192
193
Reactive web session management with pluggable session stores.
194
195
```java { .api }
196
/**
197
* Main contract for using a server-side session
198
*/
199
interface WebSession {
200
/** Get unique session ID */
201
String getId();
202
/** Get session attributes */
203
Map<String, Object> getAttributes();
204
205
/** Start the session */
206
void start();
207
/** Check if session is started */
208
boolean isStarted();
209
/** Generate new session ID */
210
Mono<Void> changeSessionId();
211
/** Invalidate the session */
212
Mono<Void> invalidate();
213
/** Save session state */
214
Mono<Void> save();
215
216
/** Check if session is expired */
217
boolean isExpired();
218
/** Get session creation time */
219
Instant getCreationTime();
220
/** Get last access time */
221
Instant getLastAccessTime();
222
223
/** Set max idle time */
224
void setMaxIdleTime(Duration maxIdleTime);
225
/** Get max idle time */
226
Duration getMaxIdleTime();
227
}
228
229
/**
230
* Main class for WebSession access and management
231
*/
232
interface WebSessionManager {
233
/** Get session for the exchange */
234
Mono<WebSession> getSession(ServerWebExchange exchange);
235
}
236
237
/**
238
* Strategy for session ID resolution
239
*/
240
interface WebSessionIdResolver {
241
/** Resolve session IDs from request */
242
List<String> resolveSessionIds(ServerWebExchange exchange);
243
/** Set session ID in response */
244
void setSessionId(ServerWebExchange exchange, String sessionId);
245
/** Expire session ID */
246
void expireSession(ServerWebExchange exchange);
247
}
248
249
/**
250
* Strategy for WebSession persistence
251
*/
252
interface WebSessionStore {
253
/** Create a new session */
254
Mono<WebSession> createWebSession();
255
/** Retrieve session by ID */
256
Mono<WebSession> retrieveSession(String sessionId);
257
/** Remove session by ID */
258
Mono<Void> removeSession(String sessionId);
259
/** Update last access time */
260
Mono<WebSession> updateLastAccessTime(WebSession webSession);
261
}
262
```
263
264
### Exception Handling
265
266
Reactive web exception handling and error processing.
267
268
```java { .api }
269
/**
270
* Contract for handling exceptions during web exchange processing
271
*/
272
interface WebExceptionHandler {
273
/** Handle the exception and return completion signal */
274
Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
275
}
276
277
/**
278
* WebExceptionHandler that can decorate the error with additional attributes
279
*/
280
interface ErrorWebExceptionHandler extends WebExceptionHandler {
281
// Marker interface for error-specific exception handlers
282
}
283
284
/**
285
* Exception thrown to trigger specific HTTP response status
286
*/
287
class ResponseStatusException extends NestedRuntimeException {
288
ResponseStatusException(HttpStatus status);
289
ResponseStatusException(HttpStatusCode status, String reason);
290
ResponseStatusException(HttpStatusCode status, String reason, Throwable cause);
291
292
/** Get HTTP status */
293
HttpStatusCode getStatusCode();
294
/** Get reason phrase */
295
String getReason();
296
}
297
298
/**
299
* Exception for method not supported
300
*/
301
class MethodNotAllowedException extends ResponseStatusException {
302
MethodNotAllowedException(HttpMethod method, Collection<HttpMethod> supportedMethods);
303
MethodNotAllowedException(String httpMethod, Collection<String> supportedMethods);
304
305
/** Get the unsupported method */
306
String getHttpMethod();
307
/** Get supported methods */
308
Set<String> getSupportedMethods();
309
}
310
311
/**
312
* Exception for unsupported media type
313
*/
314
class UnsupportedMediaTypeException extends ResponseStatusException {
315
UnsupportedMediaTypeException(String reason);
316
UnsupportedMediaTypeException(@Nullable MediaType contentType, List<MediaType> supportedTypes);
317
UnsupportedMediaTypeException(@Nullable MediaType contentType, List<MediaType> supportedTypes, ResolvableType bodyType);
318
319
/** Get the content type */
320
@Nullable
321
MediaType getContentType();
322
/** Get supported media types */
323
List<MediaType> getSupportedMediaTypes();
324
}
325
```
326
327
### Web Handler Builder
328
329
Builder for constructing reactive web handling pipeline with filters, exception handlers, and codecs.
330
331
```java { .api }
332
/**
333
* Builder for assembling reactive web handling processing pipeline
334
*/
335
class WebHttpHandlerBuilder {
336
/** Create builder with WebHandler */
337
static WebHttpHandlerBuilder webHandler(WebHandler webHandler);
338
/** Create builder from application context */
339
static WebHttpHandlerBuilder applicationContext(ApplicationContext context);
340
341
/** Add WebFilter instances */
342
WebHttpHandlerBuilder filter(WebFilter... filters);
343
/** Configure WebFilter list */
344
WebHttpHandlerBuilder filters(Consumer<List<WebFilter>> filtersConsumer);
345
346
/** Add WebExceptionHandler instances */
347
WebHttpHandlerBuilder exceptionHandler(WebExceptionHandler... handlers);
348
/** Configure WebExceptionHandler list */
349
WebHttpHandlerBuilder exceptionHandlers(Consumer<List<WebExceptionHandler>> handlersConsumer);
350
351
/** Configure message readers and writers */
352
WebHttpHandlerBuilder codecs(Consumer<ServerCodecConfigurer> codecsConsumer);
353
354
/** Set locale context resolver */
355
WebHttpHandlerBuilder localeContextResolver(LocaleContextResolver localeContextResolver);
356
/** Set forwarded header transformer */
357
WebHttpHandlerBuilder forwardedHeaderTransformer(ForwardedHeaderTransformer transformer);
358
359
/** Set WebSession manager */
360
WebHttpHandlerBuilder sessionManager(WebSessionManager sessionManager);
361
362
/** Build the HttpHandler */
363
HttpHandler build();
364
}
365
```
366
367
**Usage Examples:**
368
369
```java
370
// Build reactive web handler pipeline
371
HttpHandler handler = WebHttpHandlerBuilder
372
.webHandler(exchange -> {
373
ServerHttpResponse response = exchange.getResponse();
374
DataBuffer buffer = response.bufferFactory().wrap("Hello World".getBytes());
375
return response.writeWith(Mono.just(buffer));
376
})
377
.filter((exchange, chain) -> {
378
System.out.println("Request: " + exchange.getRequest().getPath());
379
return chain.filter(exchange);
380
})
381
.exceptionHandler((exchange, throwable) -> {
382
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
383
return exchange.getResponse().setComplete();
384
})
385
.build();
386
387
// Configure with application context
388
@Configuration
389
@EnableWebFlux
390
public class WebConfig {
391
392
@Bean
393
public HttpHandler httpHandler(ApplicationContext context) {
394
return WebHttpHandlerBuilder.applicationContext(context)
395
.filter(new CorsWebFilter(corsConfigurationSource()))
396
.exceptionHandler(new GlobalExceptionHandler())
397
.build();
398
}
399
}
400
```
401
402
### Server Web Exchange Implementation
403
404
Default implementation and builder for ServerWebExchange.
405
406
```java { .api }
407
/**
408
* Default implementation of ServerWebExchange
409
*/
410
class DefaultServerWebExchange implements ServerWebExchange {
411
DefaultServerWebExchange(ServerHttpRequest request, ServerHttpResponse response,
412
WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer,
413
LocaleContextResolver localeContextResolver);
414
415
// Implements all ServerWebExchange methods
416
}
417
418
/**
419
* Builder for mutating ServerWebExchange properties
420
*/
421
interface ServerWebExchange.Builder {
422
/** Override the request */
423
ServerWebExchange.Builder request(Consumer<ServerHttpRequest.Builder> requestBuilderConsumer);
424
/** Override the request directly */
425
ServerWebExchange.Builder request(ServerHttpRequest request);
426
427
/** Override the response */
428
ServerWebExchange.Builder response(ServerHttpResponse response);
429
430
/** Override principal */
431
ServerWebExchange.Builder principal(Mono<Principal> principalMono);
432
433
/** Build the mutated exchange */
434
ServerWebExchange build();
435
}
436
```
437
438
### Reactive Server Support Classes
439
440
Support classes for reactive web server implementations.
441
442
```java { .api }
443
/**
444
* HTTP handler adapter for different server implementations
445
*/
446
interface HttpHandler {
447
/** Handle HTTP request/response */
448
Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
449
}
450
451
/**
452
* WebHandler adapter to HttpHandler
453
*/
454
class WebHandlerAdapter implements HttpHandler {
455
WebHandlerAdapter(WebHandler delegate);
456
457
/** Set web session manager */
458
void setSessionManager(WebSessionManager sessionManager);
459
/** Set codec configurer */
460
void setCodecConfigurer(ServerCodecConfigurer codecConfigurer);
461
/** Set locale context resolver */
462
void setLocaleContextResolver(LocaleContextResolver localeContextResolver);
463
/** Set forwarded header transformer */
464
void setForwardedHeaderTransformer(ForwardedHeaderTransformer transformer);
465
/** Set application context */
466
void setApplicationContext(ApplicationContext applicationContext);
467
468
Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
469
}
470
471
/**
472
* Composite WebExceptionHandler
473
*/
474
class ExceptionHandlingWebHandler implements WebHandler {
475
ExceptionHandlingWebHandler(WebHandler delegate, WebExceptionHandler... handlers);
476
ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers);
477
478
Mono<Void> handle(ServerWebExchange exchange);
479
}
480
481
/**
482
* Composite WebFilter handler
483
*/
484
class FilteringWebHandler implements WebHandler {
485
FilteringWebHandler(WebHandler handler, WebFilter... filters);
486
FilteringWebHandler(WebHandler handler, List<WebFilter> filters);
487
488
Mono<Void> handle(ServerWebExchange exchange);
489
}
490
```
491
492
**Usage Examples:**
493
494
```java
495
// Custom WebHandler implementation
496
@Component
497
public class HelloWebHandler implements WebHandler {
498
499
@Override
500
public Mono<Void> handle(ServerWebExchange exchange) {
501
ServerHttpResponse response = exchange.getResponse();
502
response.getHeaders().add("Content-Type", "text/plain");
503
504
String message = "Hello, " + exchange.getRequest().getQueryParams().getFirst("name");
505
DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());
506
507
return response.writeWith(Mono.just(buffer));
508
}
509
}
510
511
// Custom WebFilter implementation
512
@Component
513
public class LoggingWebFilter implements WebFilter {
514
515
private static final Logger logger = LoggerFactory.getLogger(LoggingWebFilter.class);
516
517
@Override
518
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
519
long start = System.currentTimeMillis();
520
521
return chain.filter(exchange)
522
.doFinally(signalType -> {
523
long duration = System.currentTimeMillis() - start;
524
logger.info("Request {} {} completed in {}ms with status {}",
525
exchange.getRequest().getMethod(),
526
exchange.getRequest().getPath(),
527
duration,
528
exchange.getResponse().getStatusCode());
529
});
530
}
531
}
532
533
// Session handling example
534
@Component
535
public class SessionWebHandler implements WebHandler {
536
537
@Override
538
public Mono<Void> handle(ServerWebExchange exchange) {
539
return exchange.getSession()
540
.flatMap(session -> {
541
// Get or create visit count
542
Integer visitCount = session.getAttributes()
543
.compute("visitCount", (key, val) -> val == null ? 1 : (Integer) val + 1);
544
545
String message = "Visit count: " + visitCount;
546
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(message.getBytes());
547
548
return exchange.getResponse().writeWith(Mono.just(buffer));
549
});
550
}
551
}
552
```
553
554
### Error Handling and Status Pages
555
556
Built-in support for error handling and status page generation.
557
558
```java { .api }
559
/**
560
* Default error WebExceptionHandler implementation
561
*/
562
class DefaultErrorWebExceptionHandler implements ErrorWebExceptionHandler, ApplicationContextAware {
563
DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties.Resources resources,
564
ApplicationContext applicationContext);
565
566
/** Set message writers for error response */
567
void setMessageWriters(List<HttpMessageWriter<?>> messageWriters);
568
/** Set view resolvers for error pages */
569
void setViewResolvers(List<ViewResolver> viewResolvers);
570
571
Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
572
}
573
574
/**
575
* Error attributes for error information
576
*/
577
interface ErrorAttributes {
578
/** Get error attributes for the request */
579
Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options);
580
/** Get the error for the request */
581
Throwable getError(ServerRequest request);
582
/** Store error in request attributes */
583
void storeErrorInformation(Throwable error, ServerWebExchange exchange);
584
}
585
```
586
587
**Usage Examples:**
588
589
```java
590
// Custom exception handler
591
@Component
592
public class GlobalWebExceptionHandler implements WebExceptionHandler {
593
594
private final ObjectMapper objectMapper = new ObjectMapper();
595
596
@Override
597
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
598
ServerHttpResponse response = exchange.getResponse();
599
response.getHeaders().add("Content-Type", "application/json");
600
601
if (ex instanceof ResponseStatusException) {
602
ResponseStatusException rse = (ResponseStatusException) ex;
603
response.setStatusCode(rse.getStatusCode());
604
} else {
605
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
606
}
607
608
ErrorResponse error = new ErrorResponse(ex.getMessage(), System.currentTimeMillis());
609
610
try {
611
byte[] bytes = objectMapper.writeValueAsBytes(error);
612
DataBuffer buffer = response.bufferFactory().wrap(bytes);
613
return response.writeWith(Mono.just(buffer));
614
} catch (Exception e) {
615
return response.setComplete();
616
}
617
}
618
619
private static class ErrorResponse {
620
public final String message;
621
public final long timestamp;
622
623
ErrorResponse(String message, long timestamp) {
624
this.message = message;
625
this.timestamp = timestamp;
626
}
627
}
628
}
629
630
// Configuration for reactive web
631
@Configuration
632
@EnableWebFlux
633
public class ReactiveWebConfig implements WebFluxConfigurer {
634
635
@Bean
636
public WebExceptionHandler globalExceptionHandler() {
637
return new GlobalWebExceptionHandler();
638
}
639
640
@Bean
641
public CorsWebFilter corsWebFilter() {
642
CorsConfiguration corsConfig = new CorsConfiguration();
643
corsConfig.addAllowedOrigin("*");
644
corsConfig.addAllowedMethod("*");
645
corsConfig.addAllowedHeader("*");
646
647
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
648
source.registerCorsConfiguration("/**", corsConfig);
649
650
return new CorsWebFilter(source);
651
}
652
}
653
```