Intermediate 10 min WebSocket 1009

1009 Message Too Big — Payload Size Limit

อาการ

- WebSocket connection closes with code 1009 when sending or receiving a large message
- Small messages (< 64 KB) work fine; large JSON payloads or file data triggers the close
- Server logs show 'WebSocket message exceeds maximum size' with the actual vs. allowed byte count
- Python websockets library raises `websockets.exceptions.ConnectionClosedError: received 1009`
- Node.js ws library emits an error 'Max payload size exceeded'

สาเหตุหลัก

  • Server's max WebSocket message size configured too low (common defaults: 64 KB or 1 MB)
  • Client sending a large binary blob (image, file) as a single unsplit WebSocket message
  • Nginx proxy_buffer_size or client_max_body_size too small for the WebSocket frame
  • Application serializing a large object graph into a single message instead of paginating
  • Memory-protection limit preventing denial-of-service via oversized messages (intentional)

การวินิจฉัย

**Step 1 — Check the close code and the message size**

```javascript
ws.onclose = (event) => {
console.log('Code:', event.code); // 1009
console.log('Reason:', event.reason); // 'Message Too Big'
};

// Measure the payload size before sending:
const payload = JSON.stringify(largeObject);
console.log('Payload size (bytes):', new Blob([payload]).size);
```

**Step 2 — Find the server-side message size limit**

```python
# Python websockets library:
import websockets
async with websockets.serve(
handler, 'localhost', 8765,
max_size=10 * 1024 * 1024 # current limit: 10 MB
) as server:
await server.serve_forever()

# Django Channels (ASGI):
# settings.py — check CHANNEL_LAYERS and ASGI message sizes
```

```javascript
// Node.js ws library:
const wss = new WebSocket.Server({
maxPayload: 10 * 1024 * 1024 // current limit in bytes
});
```

**Step 3 — Check Nginx WebSocket proxy buffer settings**

```bash
# /etc/nginx/sites-available/yoursite:
grep -E 'proxy_buffer|client_max_body' /etc/nginx/sites-available/yoursite
# Default proxy_buffer_size is 4k — may be too small for large WS frames
```

**Step 4 — Profile the actual message sizes in production**

```python
# Add message size logging to your WebSocket handler:
async def receive(self, bytes_data=None, text_data=None):
size = len(bytes_data or text_data or b'')
if size > 512 * 1024: # warn above 512 KB
logger.warning('Large WS message', size_bytes=size)
```

การแก้ไข

**Fix 1 — Increase the server-side message size limit**

```python
# Python websockets:
await websockets.serve(handler, 'localhost', 8765, max_size=50 * 1024 * 1024) # 50 MB

# Django Channels — increase ASGI app message limit:
# In your ASGI config, wrap with a custom max_size:
from channels.routing import ProtocolTypeRouter
application = ProtocolTypeRouter({...})
```

```javascript
// Node.js ws:
const wss = new WebSocket.Server({ port: 8080, maxPayload: 50 * 1024 * 1024 });
```

**Fix 2 — Chunk large messages on the client**

```javascript
// Split large payload into chunks and reassemble on the server:
const CHUNK_SIZE = 64 * 1024; // 64 KB chunks
const messageId = crypto.randomUUID();

for (let i = 0; i * CHUNK_SIZE < payload.length; i++) {
const chunk = payload.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
const isLast = (i + 1) * CHUNK_SIZE >= payload.length;
ws.send(JSON.stringify({ id: messageId, seq: i, last: isLast, data: chunk }));
}
```

**Fix 3 — Use HTTP upload + WebSocket notification pattern**

```javascript
// Upload the large file via HTTP POST:
const formData = new FormData();
formData.append('file', largeFile);
const resp = await fetch('/api/upload', { method: 'POST', body: formData });
const { fileId } = await resp.json();

// Notify all clients via WebSocket with just the reference:
ws.send(JSON.stringify({ type: 'file_uploaded', fileId }));
```

**Fix 4 — Increase Nginx proxy buffer for WebSocket**

```nginx
location /ws/ {
proxy_pass http://upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
```

การป้องกัน

- Set explicit message size limits that match your actual use case — never use unlimited (max_size=None)
- Design the protocol to send small control messages over WebSocket and large data via HTTP
- Implement message size validation on the client before sending, with user-facing feedback
- Use binary WebSocket frames (ArrayBuffer) instead of base64-encoded text for file data — 33% smaller
- Monitor P95/P99 message sizes in production to detect growth before hitting limits

รหัสสถานะที่เกี่ยวข้อง

คำศัพท์ที่เกี่ยวข้อง