HTTP Topic
Advanced HTTP Concepts and Future Protocols
What You'll Learn:
-
HTTP/3 and QUIC protocol
-
WebSockets for real-time communication
-
Server-Sent Events (SSE) for push notifications
-
GraphQL as an alternative to REST
Detailed Explanation:
HTTP/3 and QUIC Protocol
QUIC (Quick UDP Internet Connections):
-
Transport layer protocol over UDP
-
Built-in encryption (TLS 1.3)
-
Reduced connection establishment latency
-
Improved multiplexing
HTTP/3 Benefits:
-
Faster connection setup
-
Better performance on lossy networks
-
Eliminates TCP head-of-line blocking
-
Connection migration support
WebSockets for Real-Time Communication
WebSocket Handshake:
# Client request
GET /ws/chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
# Server response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Spring WebSocket Configuration:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatWebSocketHandler(), "/ws/chat")
.setAllowedOrigins("*");
}
}
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
broadcast("User joined: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
broadcast("User " + session.getId() + ": " + payload);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
broadcast("User left: " + session.getId());
}
private void broadcast(String message) {
for (WebSocketSession session : sessions) {
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
// Handle error
}
}
}
}
Server-Sent Events (SSE)
SSE Implementation:
@RestController
@RequestMapping("/api/events")
public class EventController {
private final SseEmitterService emitterService;
@GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamEvents() {
SseEmitter emitter = new SseEmitter(30_000L); // 30 seconds timeout
emitterService.addEmitter(emitter);
emitter.onCompletion(() -> emitterService.removeEmitter(emitter));
emitter.onTimeout(() -> emitterService.removeEmitter(emitter));
return emitter;
}
@PostMapping("/notify")
public ResponseEntity<Void> sendNotification(@RequestBody Notification notification) {
emitterService.sendEvent(notification);
return ResponseEntity.ok().build();
}
}
@Service
public class SseEmitterService {
private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>();
public void addEmitter(SseEmitter emitter) {
emitters.add(emitter);
}
public void removeEmitter(SseEmitter emitter) {
emitters.remove(emitter);
}
public void sendEvent(Object event) {
List<SseEmitter> deadEmitters = new ArrayList<>();
emitters.forEach(emitter -> {
try {
emitter.send(SseEmitter.event()
.data(event)
.id(UUID.randomUUID().toString())
.name("notification"));
} catch (Exception e) {
deadEmitters.add(emitter);
}
});
emitters.removeAll(deadEmitters);
}
}
SSE Client Example:
const eventSource = new EventSource('/api/events/stream');
eventSource.onmessage = function(event) {
const notification = JSON.parse(event.data);
console.log('Received:', notification);
};
eventSource.onerror = function(event) {
console.error('SSE error:', event);
};
GraphQL as REST Alternative
GraphQL vs REST:
-
REST: Multiple endpoints, over-fetching/under-fetching
-
GraphQL: Single endpoint, client-defined responses
Spring GraphQL Implementation:
@Controller
public class UserGraphQLController {
@QueryMapping
public User user(@Argument Long id) {
return userService.findById(id);
}
@QueryMapping
public List<User> users() {
return userService.findAll();
}
@MutationMapping
public User createUser(@Argument String name, @Argument String email) {
User user = new User(name, email);
return userService.create(user);
}
@SchemaMapping
public List<Order> orders(User user) {
return orderService.findByUserId(user.getId());
}
}
GraphQL Schema:
type Query {
user(id: ID!): User
users: [User]
}
type Mutation {
createUser(name: String!, email: String!): User
}
type User {
id: ID!
name: String!
email: String!
orders: [Order]
}
type Order {
id: ID!
total: Float!
items: [OrderItem]
}
HTTP/3 Implementation
Spring Boot HTTP/3 Configuration:
# Enable HTTP/3 (experimental)
server.http3.enabled=true
# QUIC configuration
server.http3.quic.port=8443
server.http3.quic.certificate=classpath:cert.pem
server.http3.quic.private-key=classpath:key.pem
Advanced Caching with HTTP/3
Cache-Control for Modern Web:
# Modern caching strategy
Cache-Control: public, max-age=3600, stale-while-revalidate=300, stale-if-error=86400
# For immutable resources
Cache-Control: public, max-age=31536000, immutable
# For private user data
Cache-Control: private, no-cache
Performance Monitoring
HTTP/3 Metrics:
@Component
public class Http3Metrics {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer responseTimer;
public Http3Metrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("http.requests")
.tag("protocol", "http3")
.register(meterRegistry);
this.responseTimer = Timer.builder("http.response.time")
.tag("protocol", "http3")
.register(meterRegistry);
}
public void recordRequest() {
requestCounter.increment();
}
public void recordResponseTime(long duration) {
responseTimer.record(duration, TimeUnit.MILLISECONDS);
}
}
Comments (0)
No comments yet. Be the first to comment!