Handling POST Requests
Learn to read request bodies from POST requests.
Reading the Request Body
POST requests carry data in the body. To read it, you need to:
- Check the
Content-Lengthheader to know how many bytes to read - Read that many bytes from
self.rfile
python
from http.server import HTTPServer, BaseHTTPRequestHandler
class PostHandler(BaseHTTPRequestHandler):
def do_POST(self):
# Get the content length from headers
content_length = int(self.headers.get("Content-Length", 0))
# Read the body
body = self.rfile.read(content_length)
# Decode bytes to string
body_str = body.decode("utf-8")
print(f"Received: {body_str}")
# Send response
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(f"Received {len(body)} bytes".encode())
Test with curl
bash
# Send a POST request with data
curl -X POST http://localhost:8080 -d "Hello, Server!"
# Output: Received 14 bytes
Handling Missing Content-Length
Always handle the case where Content-Length might be missing:
python
def do_POST(self):
# Safely get content length
content_length = self.headers.get("Content-Length")
if content_length is None:
self.send_response(400)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Content-Length header required")
return
content_length = int(content_length)
if content_length == 0:
self.send_response(400)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Empty body not allowed")
return
# Read the body
body = self.rfile.read(content_length)
# ... process body
Reading Headers
Access any request header using self.headers:
python
def do_POST(self):
# Get specific headers
content_type = self.headers.get("Content-Type")
authorization = self.headers.get("Authorization")
custom_header = self.headers.get("X-Custom-Header")
# Check content type
if content_type != "application/json":
self.send_response(415) # Unsupported Media Type
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Content-Type must be application/json")
return
# ... continue processing
Header Names Are Case-Insensitive
HTTP headers are case-insensitive, so Content-Type,
content-type, and CONTENT-TYPE are all equivalent.
Python's self.headers.get() handles this for you.
A Complete POST Handler
python
def do_POST(self):
"""Handle POST request with validation."""
# Check content type
content_type = self.headers.get("Content-Type", "")
if "application/json" not in content_type:
self.send_error(415, "Content-Type must be application/json")
return
# Get content length
try:
content_length = int(self.headers.get("Content-Length", 0))
except ValueError:
self.send_error(400, "Invalid Content-Length")
return
if content_length == 0:
self.send_error(400, "Empty body")
return
# Read body
body = self.rfile.read(content_length)
# Process and respond
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{"status": "ok"}')