ক্লায়েন্ট-সার্ভার মডেল ও HTTP রিকোয়েস্ট-রেসপন্স সাইকেল
এই পাঠে যা শিখবেন
- ক্লায়েন্ট-সার্ভার মডেল কী এবং কেন ওয়েবের প্রতিটি ইন্টারঅ্যাকশন এই প্যাটার্ন অনুসরণ করে
- HTTP রিকোয়েস্টের অ্যানাটমি -- method, path, headers, body
- HTTP রেসপন্সের অ্যানাটমি -- status code, headers, body -- এবং status code-এর ৫টি ক্যাটাগরি
- Python দিয়ে একটি সত্যিকারের
Request/Responseজোড়া বানিয়ে একটি "সার্ভার" ফাংশনের ভেতর দিয়ে পুরো একটি রিকোয়েস্ট ট্রেস করা
১ · ক্লায়েন্ট-সার্ভার মডেল কী
ওয়েবের প্রায় প্রতিটি ইন্টারঅ্যাকশন একটি সহজ প্যাটার্ন অনুসরণ করে -- ক্লায়েন্ট-সার্ভার মডেলClient-Server Modelএকটি স্থাপত্য প্যাটার্ন যেখানে ক্লায়েন্ট রিকোয়েস্ট পাঠায় এবং সার্ভার সেটি প্রসেস করে রেসপন্স ফেরত দেয়।। ক্লায়েন্ট (সাধারণত একটি ব্রাউজার, তবে মোবাইল অ্যাপ বা অন্য কোনো প্রোগ্রামও হতে পারে) একটি রিকোয়েস্ট পাঠায় -- "আমাকে হোমপেজ দাও", "এই ফর্মটা সাবমিট করো", "আমার প্রোফাইল ডেটা দাও"। সার্ভার সেই রিকোয়েস্ট গ্রহণ করে, প্রয়োজনীয় লজিক চালায় (এবং প্রয়োজনে ডেটাবেসের সাথে কথা বলে), এবং একটি রেসপন্স ফেরত পাঠায়। এই পুরো আদান-প্রদানের প্রোটোকল হলো HTTP (HyperText Transfer Protocol)।
২ · HTTP রিকোয়েস্টের অ্যানাটমি
একটি HTTP রিকোয়েস্টের চারটি মূল অংশ থাকে -- এগুলো বুঝলে যেকোনো ব্যাক-এন্ড ফ্রেমওয়ার্কের রাউট হ্যান্ডলার কী কী তথ্য পায় তা স্পষ্ট হয়ে যায়।
কী ধরনের অ্যাকশন --
GET (ডেটা আনা), POST (নতুন কিছু তৈরি), PUT/PATCH (আপডেট), DELETE (মুছে ফেলা)।URL-এর যে অংশ কোন রিসোর্স চাওয়া হচ্ছে তা নির্দেশ করে -- যেমন
/api/login বা /users/42।মেটাডেটা -- যেমন
Content-Type (বডি কী ফরম্যাটে আছে) বা Authorization (কে রিকোয়েস্ট করছে)।প্রকৃত ডেটা পেলোড --
POST/PUT-এ সাধারণত থাকে (যেমন ফর্ম ডেটা), GET-এ সাধারণত থাকে না।৩ · HTTP রেসপন্সের অ্যানাটমি ও status code
রেসপন্সও একইভাবে গঠিত -- একটি status code (রিকোয়েস্ট সফল হলো নাকি ব্যর্থ, এবং কী কারণে, তা সংখ্যা দিয়ে জানায়), headers, ও body (প্রকৃত রেসপন্স ডেটা, সাধারণত JSON বা HTML)। Status code পাঁচটি ক্যাটাগরিতে ভাগ করা যায় -- প্রথম সংখ্যাটিই ক্যাটাগরি নির্দেশ করে।
রিকোয়েস্ট গৃহীত হয়েছে, প্রসেসিং চলছে -- ব্যবহারিক ক্ষেত্রে খুব কম দেখা যায়।
200 OK, 201 Created, 204 No Content -- রিকোয়েস্ট সফল হয়েছে।ক্লায়েন্টকে অন্য একটি URL-এ যেতে বলা হচ্ছে -- যেমন
301 Moved Permanently।ক্লায়েন্টের ভুল --
400 Bad Request, 401 Unauthorized, 404 Not Found।500 Internal Server Error -- রিকোয়েস্ট সঠিক ছিল কিন্তু সার্ভার প্রসেস করতে ব্যর্থ হয়েছে।
Python Programming কোর্সে ডিকশনারি, ক্লাস, ও
dataclass-এর সিনট্যাক্স শেখানো হয়েছে। নিচের কোড সেলে সেই ভিত্তি ব্যবহার করেই
Request ও Response-কে সত্যিকারের Python অবজেক্ট হিসেবে মডেল করা হয়েছে।
৪ · কোড সেল -- একটি পুরো রিকোয়েস্ট-রেসপন্স চক্র ট্রেস করা
নিচের কোডে একটি Request ও একটি Response ডেটাক্লাস, এবং একটি ছোট্ট "সার্ভার"
ফাংশন handle_login তৈরি করা হয়েছে যা একটি Request নিয়ে সেটার method ও body
পরীক্ষা করে একটি Response রিটার্ন করে। তিনটি ভিন্ন রিকোয়েস্ট পাঠিয়ে দেখা যাক প্রতিটির জন্য
সার্ভার কী রেসপন্স তৈরি করে।
from dataclasses import dataclass
import json
@dataclass
class Request:
method: str
path: str
headers: dict
body: str = ""
@dataclass
class Response:
status_code: int
headers: dict
body: str
def handle_login(request):
# সার্ভার লজিক -- method ও body পরীক্ষা করে সিদ্ধান্ত নেয়
if request.method != "POST":
return Response(405, {"Content-Type": "text/plain"}, "Method Not Allowed")
data = json.loads(request.body) if request.body else {}
if "username" not in data:
return Response(
400,
{"Content-Type": "application/json"},
json.dumps({"error": "username missing"})
)
return Response(
200,
{"Content-Type": "application/json"},
json.dumps({"status": "logged in", "user": data["username"]})
)
requests = [
Request("POST", "/api/login", {"Content-Type": "application/json"},
'{"username": "rina", "password": "secret"}'),
Request("POST", "/api/login", {"Content-Type": "application/json"},
'{"password": "secret"}'),
Request("GET", "/api/login", {"Content-Type": "application/json"}, ""),
]
for i, req in enumerate(requests, start=1):
print(f"=== রিকোয়েস্ট {i} ===")
print(f"Method : {req.method}")
print(f"Path : {req.path}")
print(f"Headers: {req.headers}")
print(f"Body : {req.body!r}")
resp = handle_login(req)
print("--- রেসপন্স ---")
print(f"Status : {resp.status_code}")
print(f"Headers: {resp.headers}")
print(f"Body : {resp.body}")
print()
body-তে username নেই, তাই handle_login
400 Bad Request রিটার্ন করে -- এটি ডেটার সমস্যা। রিকোয়েস্ট ৩-এ method
GET (POST নয়), তাই 405 Method Not Allowed রিটার্ন করে -- এটি ভিন্ন ধরনের ভুল।
দুটোই 4xx ক্যাটাগরির (ক্লায়েন্টের ভুল), কিন্তু নির্দিষ্ট কোড ভিন্ন কারণ ভিন্ন জিনিস ভুল ছিল -- এটাই সঠিক
status code বাছাইয়ের গুরুত্ব (এই বিষয়ে বিস্তারিত M6-এর L24-এ)।
প্রতিটি HTTP ইন্টারঅ্যাকশন একটি request → server processing → response চক্র। রিকোয়েস্টের চারটি অংশ (method, path, headers, body) সার্ভারকে বলে দেয় ক্লায়েন্ট কী চায়; রেসপন্সের তিনটি অংশ (status code, headers, body) সার্ভারের সিদ্ধান্ত ও ফলাফল ফেরত পাঠায়। এই কাঠামো বুঝলে যেকোনো ব্যাক-এন্ড ফ্রেমওয়ার্কের রাউট হ্যান্ডলার আসলে কী গ্রহণ করে ও কী রিটার্ন করে তা স্পষ্ট হয়ে যায় -- M5-এ এই ধারণাগুলোই একটি পূর্ণাঙ্গ রাউটার/মিডলওয়্যার সিস্টেমে বিস্তৃত হবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন -- তারপর "→ উত্তর" চাপুন।
প্র ০১
একটি রিকোয়েস্টে path একই থাকলেও method ভিন্ন হলে সার্ভার ভিন্ন আচরণ করতে পারে কেন?
কারণ রাউট হ্যান্ডলার path ও method দুটো মিলিয়েই সিদ্ধান্ত নেয় কোন লজিক চালাবে। যেমন /users/42
পাথে GET মানে "এই ইউজারের তথ্য দাও", কিন্তু একই পাথে DELETE মানে "এই ইউজারকে
মুছে ফেলো" -- সম্পূর্ণ ভিন্ন অ্যাকশন। একই রিসোর্সের উপর ভিন্ন অপারেশন বোঝাতেই method আলাদা রাখা হয়েছে,
যাতে একই path বারবার পুনরায় লেখা না লাগে (M6-এ REST verb-এর নিয়ম বিস্তারিত)।
প্র ০২
উপরের কোডে handle_login কেন প্রথমেই method চেক করে, body পার্স করার আগে?
কারণ যদি method ভুল হয় (যেমন GET এসেছে অথচ লগইন শুধু POST-এ কাজ করে), তাহলে
body পার্স করার কোনো মানেই নেই -- সেটা অপ্রয়োজনীয় কাজ, এবং যদি body খালি বা ভুল ফরম্যাটে
থাকে (যেমন GET রিকোয়েস্টে সাধারণত body থাকে না) তাহলে json.loads("") চালালে এরর হতে পারত।
দ্রুততম ভুলটি আগে ধরে ফেলা (fail fast) একটি ভালো সার্ভার-ডিজাইন অভ্যাস।
প্র ০৩
রেসপন্সে headers-এর মধ্যে Content-Type: application/json না থাকলে কী সমস্যা হতে পারে?
ক্লায়েন্ট (যেমন ব্রাউজারের JavaScript কোড) Content-Type হেডার দেখেই বুঝে নেয় body
কীভাবে পার্স করতে হবে -- JSON হিসেবে, নাকি সাধারণ টেক্সট বা HTML হিসেবে। এই হেডার না থাকলে বা ভুল থাকলে
ক্লায়েন্ট সঠিক body-কে ভুলভাবে পার্স করার চেষ্টা করতে পারে এবং এরর দিতে পারে, যদিও সার্ভার আসলে সঠিক ডেটাই
পাঠিয়েছিল।
অনুশীলন
-
চিন্তা করুন: আপনি যখন ব্রাউজারে একটি URL টাইপ করে Enter চাপেন, সেটি কোন HTTP method
ব্যবহার করে বলে আপনার ধারণা? আর যখন একটি লগইন ফর্ম সাবমিট করেন?
সরাসরি URL টাইপ করে Enter চাপলে ব্রাউজার একটি
GETরিকোয়েস্ট পাঠায় -- আপনি শুধু একটি পেজ "চাচ্ছেন", কিছু তৈরি বা পরিবর্তন করছেন না। লগইন ফর্ম সাবমিট করলে সাধারণতPOSTব্যবহৃত হয়, কারণ আপনি সার্ভারে ডেটা (username/password) পাঠাচ্ছেন এবং সার্ভার-সাইডে একটি অ্যাকশন (সেশন তৈরি) ঘটছে -- শুধু ডেটা "চাওয়া" হচ্ছে না। -
পরীক্ষা করুন: উপরের কোড সেলে
requestsলিস্টে একটি নতুনRequest("POST", "/api/login", {"Content-Type": "application/json"}, '{"username": "karim", "password": "1234"}')যোগ করুন এবং Run চেপে দেখুন এটি কোন status code পায়।এই রিকোয়েস্টের method
POSTএবং body-তেusername("karim") আছে, তাইhandle_login-এর দুটো চেকই পাস করবে এবং এটি200status code সহ{"status": "logged in", "user": "karim"}body ফেরত পাবে -- ঠিক রিকোয়েস্ট ১-এর মতোই সফল পথ অনুসরণ করবে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ আর্কিটেকচার প্যাটার্ন, ফ্রন্ট-এন্ড/ব্যাক-এন্ড ফ্রেমওয়ার্ক ফান্ডামেন্টাল, স্টেট ম্যানেজমেন্ট, REST API, ORM, অথেন্টিকেশন, রেন্ডারিং স্ট্র্যাটেজি ও ডিপ্লয়মেন্ট -- বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
-
JavaScript Programming কোর্স সহোদর কোর্স
ব্রাউজারে
fetch()দিয়ে বাস্তবে HTTP রিকোয়েস্ট পাঠানোর সিনট্যাক্স সেই কোর্সে অনুশীলন করা হয়েছে; এই পাঠ সেই কলের পেছনের প্রোটোকল ব্যাখ্যা করে। - সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics ও Full-Stack Web Frameworks -- সব এক জায়গায়।