ducdev
Backend / Bài viết

WebSocket — Real-time Communication Cho Web App

HTTP request-response không đủ cho chat, live notifications, hay collaborative editing. WebSocket mở kết nối hai chiều liên tục — cả server lẫn client đều có thể gửi message bất cứ lúc nào.

a
admin
10/10/2025 · 3 phút đọc · 0 lượt xem
Chia sẻ

Bạn muốn hiển thị notification ngay khi có tin nhắn mới, không cần user reload trang. Có ba cách: polling (request mỗi giây), long polling (request và chờ), hoặc WebSocket (kết nối liên tục). WebSocket là giải pháp đúng cho real-time.

HTTP Vs WebSocket

# HTTP — Request/Response
Client: "Có tin nhắn mới không?" → Server: "Không"
Client: "Có tin nhắn mới không?" → Server: "Không"
Client: "Có tin nhắn mới không?" → Server: "Có! Đây..."
# → Polling tốn tài nguyên, latency cao

# WebSocket — Bidirectional
Client → Server: Handshake (HTTP upgrade)
Server ↔ Client: Kết nối hai chiều liên tục
Server → Client: "Bạn có tin nhắn mới!"  # Server chủ động gửi

Django Channels — WebSocket Cho Django

pip install channels channels-redis

# settings.py
INSTALLED_APPS = [..., 'channels']

ASGI_APPLICATION = 'blog.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {'hosts': [('localhost', 6379)]},
    }
}

# blog/asgi.py
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import notifications.routing

application = ProtocolTypeRouter({
    'http': get_asgi_application(),
    'websocket': AuthMiddlewareStack(
        URLRouter(notifications.routing.websocket_urlpatterns)
    ),
})

WebSocket Consumer

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        user = self.scope['user']
        if not user.is_authenticated:
            await self.close()
            return

        self.group_name = f'user_{user.id}'
        # Tham gia group
        await self.channel_layer.group_add(self.group_name, self.channel_name)
        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(self.group_name, self.channel_name)

    # Nhận message từ client
    async def receive(self, text_data):
        data = json.loads(text_data)
        await self.send(text_data=json.dumps({'echo': data}))

    # Nhận message từ channel layer (group send)
    async def send_notification(self, event):
        await self.send(text_data=json.dumps({
            'type': 'notification',
            'message': event['message'],
        }))

Gửi Notification Từ Anywhere

from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

def notify_user(user_id: int, message: str):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(
        f'user_{user_id}',
        {
            'type': 'send_notification',  # Method trong Consumer
            'message': message,
        }
    )

# Dùng trong view hoặc Celery task
def create_comment(request, post_id):
    comment = Comment.objects.create(...)
    notify_user(post.author_id, f"{request.user.username} đã bình luận bài của bạn")

JavaScript Client

const ws = new WebSocket('wss://yourdomain.com/ws/notifications/');

ws.onopen = () => console.log('Connected');

ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    if (data.type === 'notification') {
        showNotification(data.message);
    }
};

ws.onclose = (event) => {
    // Auto-reconnect sau 3 giây
    setTimeout(() => reconnect(), 3000);
};
WebSocket không phải là replacement cho HTTP — nó bổ sung cho HTTP trong những use case cụ thể: chat, live updates, collaborative editing, gaming. Đừng dùng WebSocket cho những thứ HTTP đủ dùng.

Kết Luận

Django Channels mở rộng Django để hỗ trợ async protocols. Với Redis làm channel layer, bạn có thể scale WebSocket across multiple server instances. Bước tiếp theo: tìm hiểu Server-Sent Events (SSE) — đơn giản hơn WebSocket cho use case one-way (server → client).

#WebSocket #Django Channels #Real-time #backend #Python
a
Tác giả
admin

Lập trình viên, yêu thích chia sẻ kiến thức về công nghệ và phát triển phần mềm.

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!

Để lại bình luận

Bình luận sẽ được duyệt trước khi hiển thị.