AJAX ফর্ম JSON আশা করে কিন্তু HTML পায়: প্রতিক্রিয়া ধাপে ধাপে যাচাই করুন
200 স্ট্যাটাস JSON-এর প্রমাণ নয়। নেটওয়ার্ক প্যানেল ধাপে ধাপে অনুসরণ করে পরিবহন, উপস্থাপন ও চুক্তির ব্যর্থতা আলাদা করুন।
ফর্ম জমা হয়, স্পিনার দেখা যায়, আর কনসোল বলে JSON-এ অবস্থান 0-এ অপ্রত্যাশিত চিহ্ন <। পৃষ্ঠাটি নিজে ঠিকঠাক লোড হয়, তাই প্রথম প্রবণতা পার্সার বা টানেলকে দোষ দেওয়া। সাধারণত দুটোর কোনোটিই জড়িত নয়: জমা দেওয়াটি পৃষ্ঠা লোডের চেয়ে আলাদা অনুরোধ, এবং এটি এমন কিছু নিয়ে ফিরেছে যা JSON নয়। ব্রাউজার যে ক্রমে তা প্রকাশ করে সেই ক্রমেই কাজ করুন, কারণ চারটি সম্ভাব্য উত্তর চারটি ভিন্ন সংশোধন চায়।
ধাপ 1: সত্যিই যে জমা হয়েছে তা ধরে নিন
জমা দেওয়ার আগে নেটওয়ার্ক প্যানেল খুলুন, নেভিগেশনের মধ্যে এন্ট্রি সংরক্ষণ করতে লগ সেট করুন, তারপর যে অ্যাকাউন্ট ব্যবহার করার অনুমতি আছে সেখানে একটি নিরীহ পরীক্ষামূলক জমা দিন। পৃষ্ঠার ডকুমেন্ট অনুরোধ নয়, ফর্ম নিজেই যে অনুরোধ শুরু করেছে সেটি বাছুন।
ফিল্টার নিয়ে সতর্ক থাকুন। XHR বা Fetch ফিল্টার সুবিধাজনক, কিন্তু ফ্রেমওয়ার্ক যদি এখনও লুকানো iframe বা গতিশীলভাবে তৈরি ফর্ম দিয়ে জমা দেয়, ফিল্টার একমাত্র গুরুত্বপূর্ণ অনুরোধটিই লুকিয়ে ফেলবে। প্রথমে ফিল্টার ছাড়া একবার জমা দিয়ে দেখুন কী এল।
বাছাই করা অনুরোধের জন্য ব্যাখ্যার আগে ছয়টি জিনিস লিখুন: মেথড, কোয়েরি স্ট্রিংসহ পূর্ণ URL, স্ট্যাটাস, রিডাইরেক্ট শৃঙ্খল, প্রতিক্রিয়ার Content-Type এবং বডির প্রথম কয়েক লাইন। Chrome DevTools-এর নেটওয়ার্ক প্যানেল রেফারেন্স Headers, Response ও Initiator ভিউ কভার করে, অন্য ব্রাউজারের সমতুল্য প্যানেলও একই ফিল্ড দেখায়।
ধাপ 2: এটি আপনার ভাবা অনুরোধই কি না নিশ্চিত করুন
অনেক JSON ত্রুটি আসলে রাউটিং ত্রুটি। সাবমিট হ্যান্ডলার preventDefault ডাকার আগেই যদি throw করে, ব্রাউজার action অ্যাট্রিবিউটে লেখা ঠিকানায় নেটিভ ফর্ম POST করে, সার্ভার পূর্ণ HTML পৃষ্ঠা ফেরায়। হ্যান্ডলার চলে না, তাই JSON কখনোই চাওয়া হয়নি।
প্যানেলের URL আপনার JavaScript যে URL ডাকে তার সঙ্গে মেলান। অন্য জায়গায় শেষ হওয়া রিডাইরেক্ট, অনুপস্থিত বা অতিরিক্ত শেষ স্ল্যাশ, মেথড মিসম্যাচ, বা সরানো পৃষ্ঠা থেকে আপেক্ষিক পথে পোস্ট করা ফর্ম খুঁজুন। রিডাইরেক্ট শৃঙ্খল শেষ পর্যন্ত অনুসরণ করে চূড়ান্ত URL লক্ষ্য করুন, প্রথমটি নয়।
তারপর ইনিশিয়েটর দেখুন। অনুরোধটি আপনার স্ক্রিপ্টের বদলে ডকুমেন্ট নেভিগেশন থেকে এলে সমস্যা ইতিমধ্যেই পেয়েছেন, পার্সার বদলে কিছুই কাজে আসবে না।
ধাপ 3: ফলাফলকে চার শ্রেণিতে ভাগ করুন
প্রতিটি ফল ঠিক এগুলোর একটিতে পড়ে, আর শ্রেণিই ঠিক করে এরপর কোথায় দেখবেন।
| What you see | Category | Where to look |
|---|---|---|
| Request never finishes, TLS or connection error | No usable response | Endpoint reachability, certificate, front-end timeout |
| Request completes, script gets an opaque failure | Access blocked | Cross-origin policy, credentials mode, missing response header |
| 200 with an HTML body or a login form | Wrong representation | Redirect, expired session, route fallback, error handler |
| Body begins with a notice then valid JSON | Wrong representation | Server-side warning output before serialisation |
| Valid JSON, framework rejects it | Contract mismatch | Envelope shape, field names, value types |
মাঝের সারিগুলোই মানুষ ভুল নির্ণয় করে, কারণ স্ট্যাটাস 200। রিডাইরেক্টের পর পাওয়া সাইন-ইন পৃষ্ঠা সম্পূর্ণ ভালো HTTP প্রতিক্রিয়া এবং খুব খারাপ JSON ডকুমেন্ট। application/json কনটেন্ট টাইপ তা সারায় না: এটি একটি লেবেল, আর ভুল লেবেল লাগানো বডিও পার্স হতে ব্যর্থ হয়। অ্যাক্সেস ব্লকড সারিটি সম্পূর্ণ অনুরোধের মতো দেখায়: প্যানেল স্ট্যাটাস দেখায়, কিন্তু ক্রস-অরিজিন নীতি বডি আটকে রাখে, তাই ডাকা স্ক্রিপ্টের কাছে এটি টাইমআউটের মতোই অচল।
চতুর্থ সারিটি পুরনো PHP ও ফ্রেমওয়ার্ক স্ট্যাকে সমান সাধারণ। এনকোডেড পেলোডের আগে ছাপা ডেপ্রিকেশন নোটিশ এমন বডি তৈরি করে যা কোনো JSON পার্সার মানে না, আর সেই নোটিশই প্রায়ই পুরো ব্যাখ্যা।
ধাপ 4: পার্সারের ত্রুটি আক্ষরিকভাবে পড়ুন
ত্রুটির লেখা যে প্রথম অক্ষরটি পার্স ভেঙেছে তার নাম বলে, যা সাধারণত কোনো অনুমান ছাড়াই শ্রেণি চিনিয়ে দেয়।
| Error text (Chrome/V8) | What it means |
|---|---|
| Unexpected token < in JSON at position 0 | The body starts with markup: an HTML page or an error document |
| Unexpected end of JSON input | Empty body, or the response was truncated |
| Unexpected token o in JSON at position 1 | You parsed something already parsed, typically an object rather than text |
| Unexpected token u | The body starts with the bare word undefined, usually an empty response rendered as a string |
200 সহ খালি বডি আলাদা ঘটনা: এন্ডপয়েন্ট চলেছে, কিছু তৈরি করেনি, আর নিচের কিছু তা সফলতা ধরেছে। এটি পরিবহন নয়, অ্যাপ্লিকেশন চুক্তির ব্যর্থতা, এবং এর জায়গা প্রক্সিতে নয় পরের ধাপে। Firefox ও Safari একই চারটি ব্যর্থতা ভিন্ন ভাষায় লেখে, তাই সঠিক স্ট্রিং নয়, অক্ষর বা খালি বডিতে মেলান।
ধাপ 5: প্রমাণ যে স্তর দেখাচ্ছে সেটি ঠিক করুন
রাউটিং সমস্যায় অনুরোধ ঠিক করুন: action সংশোধন করুন, হ্যান্ডলারকে নিচে পড়তে দেবেন না, এন্ডপয়েন্ট ও মেথড মিলান, আবার পরীক্ষা করুন। উপস্থাপন সমস্যায় বডি যা তৈরি করেছে তা ঠিক করুন, আর ডেটা প্রত্যাশিত জায়গায় ত্রুটি ডকুমেন্ট কেন ফিরছে তা বের করুন। চুক্তি সমস্যায় আপনার চালানো সংস্করণের জন্য ফ্রেমওয়ার্কের প্রকৃত প্রত্যাশিত গঠন পড়ুন, ক্লায়েন্ট ঢিলা করার বদলে প্রতিক্রিয়া সেই মোতাবেক গড়ুন।
অ্যাক্সেস ব্লকড প্রতিক্রিয়ার আলাদা ধাপ দরকার, কারণ অনুরোধ নিজেই সঠিক হতে পারে আর বডি আপনার কোডে না-ও পৌঁছাতে পারে। প্রতিক্রিয়ার Access-Control-Allow-Origin ব্রাউজারের পাঠানো নির্দিষ্ট Origin-এর সঙ্গে মেলান, মনে রাখুন ওয়াইল্ডকার্ড ক্রেডেনশিয়ালযুক্ত অনুরোধ মেটায় না। ক্লায়েন্টে credentials: 'include' সার্ভারে Access-Control-Allow-Credentials: true-এর সঙ্গে জোড়া দিন, আর দেখুন কলে no-cors মোড ব্যবহৃত হয়েছে কি না, যেখানে অস্বচ্ছ বডি বাগ নয় ডকুমেন্টেড ফল।
পার্সারকে বেশি সহনশীল কিছু দিয়ে বদলানো একমাত্র সংশোধন যা এড়ানো উচিত। প্রতিক্রিয়া কোড হিসেবে মূল্যায়ন করা, বা পার্স না হওয়া পর্যন্ত লেখা ছাঁটা চুক্তির অমিল লুকায় আর নীরবতার বিনিময়ে ইনজেকশনের পৃষ্ঠ যোগ করে। একইভাবে স্ট্যাটাস বডি থেকে আলাদা যাচাই জরুরি: অ্যাপ্লিকেশন স্তরের ত্রুটি অবজেক্টসহ 200 অনেক API-তে স্বাভাবিক এবং পেলোড পড়ে সামলাতে হয়।
অন্যের সাহায্য লাগলে কাঁচা এক্সপোর্ট নয়, ন্যূনতম রেকর্ড ভাগ করুন — মেথড, URL, স্ট্যাটাস, রিডাইরেক্টের পর চূড়ান্ত URL, প্রতিক্রিয়ার কনটেন্ট টাইপ, বডির আকার আর প্রত্যাশিত চুক্তি। নেটওয়ার্ক আর্কাইভে কুকি, টোকেন, কোয়েরি স্ট্রিং আর ফর্মে থাকা ব্যক্তিগত তথ্য থাকে, আর স্বয়ংক্রিয় স্যানিটাইজার পর্যালোচনা নয়।
- কোনো কোড বদলানোর আগে ফিল্টার ছাড়া অনুরোধটি ধরুন।
- ইনিশিয়েটর আপনার স্ক্রিপ্ট ছিল আর চূড়ান্ত URL আপনার এন্ডপয়েন্ট, নিশ্চিত করুন।
- পার্সার ছোঁয়ার আগে প্রতিক্রিয়া শ্রেণিবদ্ধ করুন।
- রাউটিং, অ্যাক্সেস, উপস্থাপন বা চুক্তি ঠিক করুন, পার্সার ঢিলা করে কখনো নয়।