فرم AJAX انتظار JSON دارد اما HTML میگیرد: پاسخ را گام به گام بررسی کنید
پاسخ 200 اثبات JSON بودن نیست. پنل شبکه را گام به گام دنبال کنید و خرابی انتقال، نمایش و قرارداد را از هم جدا کنید.
فرم ارسال میشود، نشانگر ظاهر میشود و کنسول میگوید نشانهٔ < غیرمنتظره در JSON در موقعیت 0 هست. خود صفحه خوب بارگذاری میشود و همین باعث میشود نخستین واکنش، متهم کردن تحلیلگر یا تونل باشد. معمولاً هیچکدام درگیر نیستند: ارسال، درخواستی متفاوت از بارگذاری صفحه است و با چیزی برگشته که JSON نیست. به ترتیبی کار کنید که مرورگر واقعاً آن را آشکار میکند، چون چهار پاسخ ممکن به چهار اصلاح متفاوت نیاز دارند.
گام 1: ارسالی را که واقعاً رخ داد بگیرید
پیش از ارسال پنل شبکه را باز کنید، گزارش را طوری تنظیم کنید که ورودیها در جابهجاییها بمانند و سپس یک ارسال آزمایشی بیخطر روی حسابی که اجازهٔ استفاده از آن را دارید انجام دهید. درخواستی را انتخاب کنید که خود فرم آغاز کرده، نه درخواست سند صفحه.
مراقب صافیها باشید. صافی XHR یا Fetch راحت است، اما اگر چارچوب هنوز از طریق iframe پنهان یا فرمی که پویا ساخته میشود ارسال کند، صافی تنها درخواست مهم را پنهان میکند. نخست یک بار بدون صافی ارسال کنید و ببینید چه آمد.
برای درخواست انتخابی، پیش از هر تفسیری شش چیز را ثبت کنید: متد، URL کامل همراه با رشتهٔ پرسوجو، وضعیت، زنجیرهٔ تغییرمسیر، Content-Type پاسخ و نخستین خطوط بدنه. مرجع پنل شبکه در Chrome DevTools نماهای Headers، Response و Initiator را که اینها در آنها هستند پوشش میدهد و پنلهای معادل در مرورگرهای دیگر همان فیلدها را نشان میدهند.
گام 2: تأیید کنید همان درخواستی است که فکر میکنید
شمار شگفتآوری از خطاهای JSON در واقع خطاهای مسیریابی هستند. اگر گردانندهٔ ارسال پیش از فراخوانی preventDefault استثنا بیندازد، مرورگر یک POST بومی فرم به همان جایی میفرستد که ویژگی action میگوید و سرور با صفحهٔ کامل HTML پاسخ میدهد. گرداننده هرگز اجرا نمیشود، پس هرگز JSON درخواست نشده است.
URL پنل را با URLی که JavaScript شما صدا میزند مقایسه کنید. به دنبال تغییرمسیری باشید که جای دیگری تمام میشود، اسلش پایانی کم یا زیاد، ناسازگاری متد جایی که گرداننده GET میفرستد و نقطهٔ پایانی POST میپذیرد، یا فرمی که به مسیری نسبی از صفحهای که جابهجا شده ارسال میکند. زنجیرهٔ تغییرمسیر را تا انتها دنبال کنید و 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 نهایی نقطهٔ پایانی شماست.
- پیش از دست زدن به تحلیلگر پاسخ را دستهبندی کنید.
- مسیریابی، دسترسی، نمایش یا قرارداد را اصلاح کنید و هرگز با شل کردن تحلیلگر نه.