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 ваша крајња тачка.
- Класификујте одговор пре него што дотакнете парсер.
- Поправите усмеравање, приступ, приказ или уговор и никада олабављивањем парсера.