Помилка WordPress REST API: що ламає REST і як усувати неполадки

Було корисно?

Деякі збої WordPress голосні: білі екрани, фатальні помилки, ті, які помічаєш перш ніж охолоне кава. Збої REST API тихіші й дратують більше. Ваш редактор не зберігає, безголовий фронтенд стає пустим, WooCommerce іноді оформляє замовлення «інколи», і єдина підказка — зарозуміле повідомлення на кшталт «The REST API encountered an error».

Практична реальність така: REST API — це не одна функція. Це ланцюг — перезаписи, маршрутизація, автентифікація, cookies/nonce, шари кешування, проміжні захисні механізми та хостинг — і кожен з них може ламатися окремо. Ми виявимо, яке посилання зламалося, з командами, які ви можете виконати, виводами, які зможете інтерпретувати, і рішеннями, які можна прийняти без гадань.

Як WordPress REST фактично працює (і де він ламається)

Коли хтось каже «WordPress REST API зламався», зазвичай мають на увазі одне з наступного:

  • Маршрут недоступний (перезаписи, постійні посилання, конфігурація сервера, зворотний проксі, CDN або WAF заважають).
  • Маршрут доступний, але заблоковано (проблеми авторизації, nonce/cookie, перевірки прав, плагіни безпеки або правила WAF).
  • Маршрут виконується та аварійно завершується (фатальна помилка PHP, таймаути БД, ліміти пам’яті, код плагіна, помилки серіалізації).
  • Маршрут виконується, але відповідь спотворюється (кешування, компресія, зміна content-type, несподівані редиректи, змішаний контент, CORS).

На здоровому сайті канонічна базова кінцева точка:

  • /wp-json/ (JSON-індекс неймспейсів і маршрутів)
  • Приклад маршруту: /wp-json/wp/v2/posts

Під капотом WordPress використовує правила перезапису, щоб направляти /wp-json/... до index.php, де REST-сервер делегує обробку зареєстрованим маршрутам. Це означає, що навіть «API»-збої часто починаються як нудні помилки перезапису.

Також: REST-запити — це просто HTTP-запити. Це сила й слабкість. Кожний проміжний елемент, що «допомагав» вебсайту (кеш, CDN, фаєрвол, блокувальник ботів, фільтр gzip, мінімізатор, «зміцнювач безпеки»), може «допомогти» вашому REST API потрапити в могилу.

Одна операційна цитата, щоб не обманювати себе:

«Сподівання — не стратегія.» — ген. Гордон Р. Салліван

Де збігаються відмови

У продакшені проблеми REST API концентруються навколо п’яти шарів:

  1. DNS/TLS/edge: сертифікати, невідповідність SNI, редиректи HTTP→HTTPS, кешування CDN, блокування WAF.
  2. Зворотний проксі / вебсервер: перезаписи Nginx/Apache, нормалізація шляхів, обрізання заголовків, обмеження тіла запиту.
  3. Шар додатка WordPress: налаштування постійних посилань, реєстрація маршрутів, конфлікти плагінів, логіка автентифікації і nonce.
  4. Стан і зберігання: блокування/таймаути БД, дивна поведінка object cache, права на файлову систему.
  5. Поведінка клієнта: JS-фронтенд, редактор Gutenberg, CORS, змішані cookies, застарілі nonce.

Не починайте діагностику з інтерфейсу адміністратора WordPress. Це як діагностувати мережевий збій, дивлячись на шпалери робочого столу. Почніть із запиту з-поза браузера з відомими вхідними даними та очікуваними виходами.

Швидка інструкція діагностики

Коли REST «впав», вам потрібна відповідь за кілька хвилин: це edge/proxy, додаток чи бекенд? Використовуйте цю інструкцію послідовно. Не пропускайте кроки, бо ви «вже знаєте». Саме так інциденти перетворюються на спогади.

По-перше: підтвердіть кінцеву точку та HTTP-правду

  1. Запитайте /wp-json/ через curl і зафіксуйте: код статусу, content-type і будь-які редиректи.
  2. Порівняйте з двох точок: з вашого ноутбука і з сервера (або з машини в тій же мережі, що й WordPress).
  3. Перевірте HTML замість JSON. HTML часто означає, що ви отримуєте сторінку входу, блок-сторінку WAF або кешований шаблон помилки.

По-друге: ізолюйте edge/безпеку від WordPress

  1. Обійдіть CDN, якщо можливо (прямий origin-хост, VIP внутрішнього балансувальника навантаження або запис у hosts файл у контрольованому середовищі).
  2. Перегляньте логи WAF/плагінів безпеки на предмет блокувань /wp-json і типових сигнатур (помилкові спрацьовування SQLi/XSS).
  3. Підтвердіть відсутність зациклених редиректів (HTTP→HTTPS→HTTP, www→non-www, правила trailing slash).

По-третє: підтвердіть маршрутизацію WordPress і перезаписи

  1. Переконайтеся, що постійні посилання не встановлені в «Plain». REST може працювати в plain-режимі, але перезаписи часто стають непослідовними, коли люди перемикають налаштування без очищення правил.
  2. Підтвердіть, що правила перезапису існують у конфігурації сервера (правила location Nginx) або в .htaccess (Apache).
  3. Перевірте, чи працює index.php?rest_route=/. Якщо так — перезаписи зламані; якщо ні — проблема в додатку або блокуванні.

По-четверте: автентифікація лише після того, як шлях працює

  1. Спочатку перевіряйте публічні кінцеві точки (список записів), потім приватні (користувачі, налаштування).
  2. Якщо потрібна автентифікація, тестуйте з Application Passwords або Basic Auth (у безпечному середовищі), щоб прибрати складність nonce/cookie.
  3. Потім перевіряйте cookie+nonce-потоки для проблем з редактором.

По-п’яте: якщо все повільно або 500-ить, розглядайте як насичення бекенду

  1. Корелюйте з насиченням PHP-FPM, повільними запитами до БД і логами помилок.
  2. Візьміть вибірку невдалих запитів і простежте: лог доступу вебсервера → лог помилок PHP → WP debug лог → логи БД.
  3. Прийміть рішення: відкат плагіну/теми, масштабування або тимчасове пом’якшення через виключення кешування.

Правило прийняття рішення: Якщо /wp-json/ не повертає стабільний 200 з JSON з двох точок, не витрачайте час на налагодження функцій WordPress. Виправте маршрутизацію/edge перш за все.

Карта симптомів: розшифровка помилок за поведінкою HTTP

Помилки REST часто з’являються як загальне повідомлення в адмінці WordPress. Ігноруйте повідомлення і дивіться HTTP.

Коди статусу і що вони зазвичай означають

  • 200, але неправильний content-type (HTML): ви потрапили на сторінку входу, блок-сторінку WAF, кешований шаблон помилки або ціль редиректу.
  • 301/302 зациклення: канонізаційні правила конфліктують (HTTP/HTTPS, www/non-www, trailing slash), або заголовки проксі неправильно встановлені.
  • 401 Unauthorized: відсутні/некоректні облікові дані, помилка nonce, Application Passwords вимкнені, плагін безпеки перехоплює.
  • 403 Forbidden: правило WAF/CDN, mod_security, обмеження IP, «блокувати JSON-запити», або перевірка прав, що провалюється.
  • 404 Not Found: перезаписи не працюють, невідповідність location Nginx, баги мультисайту або маршрути не зареєстровані.
  • 405 Method Not Allowed: проксі/сервер забороняє POST/PUT, або шар кешування дозволяє тільки GET.
  • 413 Payload Too Large: обмеження розміру тіла проксі; завантаження через REST і медіа-ендпоінти падають.
  • 429 Too Many Requests: ліміт запитів, WAF, захист від ботів або агресивне обмеження плагіну.
  • 500/502/503: фатальна помилка PHP, аварія апстріму, вичерпано php-fpm, таймаут БД, origin недоступний або таймаут шлюзу.

Жарт #1: REST API «станний» — це мило, ніби називати малюка «тихий» за п’ять хвилин до того, як цукор подіє.

Практичні завдання (команди, виводи, рішення)

Це не «поради». Це повторювані завдання. Кожне містить команду, що означає вивід і яке рішення приймати далі.

Завдання 1: Перевірте індекс REST з вашої робочої станції

cr0x@server:~$ curl -sS -D- -o /tmp/rest.json https://example.com/wp-json/ | head -n 20
HTTP/2 200
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
x-content-type-options: nosniff

Що означає вивід: Отримано 200 і content-type JSON. Добре: маршрутизація і базовий шлях відповіді працюють зовні.

Рішення: Перейдіть до перевірок, пов’язаних з автентифікацією та плагінами. Якщо бачите 301/302 — слідуйте за редиректами (-L) і проаналізуйте канонізацію. Якщо content-type — text/html, ви не отримуєте REST API.

Завдання 2: Перевірте, чи отримуєте HTML замість JSON

cr0x@server:~$ curl -sS -D- https://example.com/wp-json/ | sed -n '1,25p'
HTTP/2 403
content-type: text/html; charset=UTF-8
server: cloudflare

<!doctype html>
<html>
<head><title>Access denied</title></head>

Що означає вивід: 403 з HTML-блок-сторінкою і хедером CDN/server. Це не WordPress. Це проблема на edge.

Рішення: Припиніть чіпати WordPress. Розслідуйте правила WAF/CDN/фаєрволу і обійдіть edge, щоб підтвердити здоров’я origin.

Завдання 3: Протестуйте з origin-хоста, щоб обійти CDN/WAF (де можливо)

cr0x@server:~$ curl -sS -D- -H 'Host: example.com' http://127.0.0.1/wp-json/ | head -n 15
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
X-Powered-By: PHP/8.2.12

Що означає вивід: Origin повертає JSON нормально. Edge — проблема.

Рішення: Виправте політику edge: дозвольте /wp-json/*, дозвольте потрібні методи, відрегулюйте правила ботів або додайте виключення WAF для REST-ендпоінтів (строго обмежене).

Завдання 4: Визначте, чи зламані перезаписи, використовуючи rest_route

cr0x@server:~$ curl -sS -D- "https://example.com/index.php?rest_route=/" | head -n 15
HTTP/2 200
content-type: application/json; charset=UTF-8

Що означає вивід: REST API працює, коли ви обходите перезаписи. Отже, шар перезаписів зламаний.

Рішення: Виправте конфігурацію серверних перезаписів або скиньте пермалінки. Не витрачайте час на налагодження плагінів, поки /wp-json/ не працюватиме як index.php?rest_route=/.

Завдання 5: Перевірте модулі перезапису Apache та стан .htaccess

cr0x@server:~$ sudo apachectl -M | egrep 'rewrite|headers'
 rewrite_module (shared)
 headers_module (shared)

Що означає вивід: Потрібні модулі існують. Якщо rewrite відсутній, пермалінки і REST-маршрути часто не працюють.

Рішення: Якщо rewrite_module відсутній — увімкніть його і перезавантажте Apache. Якщо присутній — перевірте vhost і правила .htaccess далі.

Завдання 6: Перевірте маршрутизацію Nginx для wp-json (поширена проблема)

cr0x@server:~$ sudo nginx -T 2>/dev/null | sed -n '/server_name example.com/,/}/p' | egrep -n 'location|try_files|rewrite'
12:    location / {
13:        try_files $uri $uri/ /index.php?$args;
14:    }
28:    location ~ \.php$ {
29:        include snippets/fastcgi-php.conf;
30:        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
31:    }

Що означає вивід: Нормальний fallback try_files перенаправляє невідомі шляхи (включно з /wp-json/) до index.php.

Рішення: Якщо бачите try_files $uri =404; без fallback на index, виправте його або REST буде повертати 404. Після змін перезавантажте Nginx і повторіть тест.

Завдання 7: Переконайтеся, що WordPress вважає site URL реальним

cr0x@server:~$ wp option get siteurl --path=/var/www/html
https://example.com
cr0x@server:~$ wp option get home --path=/var/www/html
https://example.com

Що означає вивід: Ці URL керують канонічними редиректами і cookies. Невідповідність (http проти https, www проти non-www) ламає nonce/cookie-автентифікацію і створює циклі редиректів.

Рішення: Якщо вони неправильні — виправте обережно, після чого перевірте редиректи і REST-запити.

Завдання 8: Перегляньте правила перезаписів WordPress і безпечно скиньте їх

cr0x@server:~$ wp rewrite list --path=/var/www/html | head -n 12
^wp-json/?$		index.php?rest_route=/	last
^wp-json/(.+)?$	index.php?rest_route=/$matches[1]	last
^wp-sitemap\.xml$	index.php?sitemap=index	last

Що означає вивід: Правила перезаписів REST існують на рівні WordPress.

Рішення: Якщо вони відсутні — скиньте правила:

cr0x@server:~$ wp rewrite flush --hard --path=/var/www/html
Success: Rewrite rules flushed.

Рішення: Якщо WordPress має правила, але HTTP все одно 404 — ваш вебсервер їх ігнорує (конфігурація Nginx, Apache AllowOverride тощо).

Завдання 9: Перевірте, чи Apache дозволяє переоприділення через .htaccess

cr0x@server:~$ sudo apachectl -S 2>/dev/null | sed -n '1,80p'
VirtualHost configuration:
*:80                   example.com (/etc/apache2/sites-enabled/example.conf:1)

cr0x@server:~$ sudo sed -n '1,120p' /etc/apache2/sites-enabled/example.conf | egrep -n 'DocumentRoot|Directory|AllowOverride'
2: DocumentRoot /var/www/html
5: <Directory /var/www/html>
6:     AllowOverride None
7: </Directory>

Що означає вивід: AllowOverride None означає, що ваш .htaccess ігнорується. Пермалінки і перезаписи REST не працюватимуть, якщо vhost не має еквівалентних правил перезапису.

Рішення: Встановіть AllowOverride All (або явно додайте правила перезапису у vhost), перезавантажте Apache і повторіть тест /wp-json/.

Завдання 10: Ідентифікуйте, чи плагін перехоплює REST-запити

cr0x@server:~$ wp plugin list --status=active --path=/var/www/html
+-------------------------+--------+-----------+---------+
| name                    | status | update    | version |
+-------------------------+--------+-----------+---------+
| wordfence               | active | none      | 7.11.6  |
| w3-total-cache          | active | available | 2.7.5   |
| classic-editor          | active | none      | 1.6.7   |
+-------------------------+--------+-----------+---------+

Що означає вивід: Плагіни безпеки і кешування — часті винуватці проблем REST. Це не звинувачення; це ймовірність.

Рішення: Тимчасово відключіть підозрілі плагіни (у контрольований час) і повторіть тест. Почніть з плагінів WAF/безпеки та агресивних кеш-плагінів.

Завдання 11: Тимчасово відключіть плагіни, не руйнуючи продакшен сліпо

cr0x@server:~$ wp plugin deactivate wordfence w3-total-cache --path=/var/www/html
Plugin 'wordfence' deactivated.
Plugin 'w3-total-cache' deactivated.

Що означає вивід: Ви перевіряєте, чи відновиться REST після видалення перехоплення.

Рішення: Якщо REST відновлюється — вмикайте по одному плагіну, щоб ізолювати проблему. Потім налаштуйте: дозволити /wp-json/, вимкнути блокування REST, виключити кешування для REST-ендпоінтів.

Завдання 12: Перевірте помилки, пов’язані з REST, у логах PHP

cr0x@server:~$ sudo tail -n 40 /var/log/php8.2-fpm.log
[27-Dec-2025 10:12:41] WARNING: [pool www] child 1842 said into stderr: "PHP Warning:  Cannot modify header information - headers already sent in /var/www/html/wp-content/plugins/some-plugin/plugin.php on line 88"
[27-Dec-2025 10:12:41] WARNING: [pool www] child 1842 said into stderr: "PHP Fatal error:  Uncaught TypeError: json_encode(): Argument #2 ($flags) must be of type int, string given in /var/www/html/wp-content/plugins/some-plugin/api.php:55"

Що означає вивід: Така фатальна помилка може перетворити API-запит у 500, і WordPress повідомить «REST API encountered an error».

Рішення: Відкотіть плагін/тему до раніше працюючої версії, виправте код або зафіксуйте версію PHP, якщо виникла несумісність. Виправлення фатальної помилки — обов’язкове.

Завдання 13: Перевірте журнали доступу Nginx/Apache щодо статусів і таймінгу апстріму

cr0x@server:~$ sudo tail -n 20 /var/log/nginx/access.log | egrep 'wp-json|rest_route' | tail -n 5
203.0.113.10 - - [27/Dec/2025:10:13:02 +0000] "GET /wp-json/ HTTP/2.0" 200 2534 "-" "curl/8.5.0"
203.0.113.10 - - [27/Dec/2025:10:13:05 +0000] "POST /wp-json/wp/v2/posts HTTP/2.0" 401 214 "-" "Mozilla/5.0"
203.0.113.10 - - [27/Dec/2025:10:13:08 +0000] "GET /index.php?rest_route=/wp/v2/users/me HTTP/2.0" 200 612 "-" "Mozilla/5.0"

Що означає вивід: Публічний GET працює, автентифікований POST повертає 401, але автентифікований запит через rest_route працює (можливо з cookies). Це вказує на відмінності в потоках автентифікації, обрізані заголовки або проблеми з nonce.

Рішення: Зосередьтеся на автентифікації: cookies, nonce, Application Passwords, заголовки зворотного проксі або плагіни безпеки, що по-різному обробляють POST до /wp-json.

Завдання 14: Підтвердіть, що проксі не обрізає заголовки відповіді

cr0x@server:~$ curl -sS -D- -o /dev/null https://example.com/wp-json/ | egrep -i 'content-type|cache-control|vary|www-authenticate|set-cookie'
content-type: application/json; charset=UTF-8
cache-control: no-cache, must-revalidate, max-age=0
vary: Accept-Encoding

Що означає вивід: Для багатьох REST-ендпоінтів правильна поведінка cache-control важлива. Відсутність Set-Cookie при потоках входу або відсутність WWW-Authenticate при 401 також можуть сигналізувати про обрізання заголовків.

Рішення: Якщо заголовки відрізняються між origin і edge — виправте конфіг проксі (передачу заголовків) або поведінку CDN. REST і «розумне» кешування за замовчуванням не друзі.

Завдання 15: Перевірте, чи працює базова автентифікація REST з Application Password

cr0x@server:~$ curl -sS -u "apiuser:abcd efgh ijkl mnop" https://example.com/wp-json/wp/v2/users/me | head
{"id":2,"name":"API User","url":"","description":"","link":"https:\/\/example.com\/author\/apiuser\/"}

Що означає вивід: Автентифікація працює і WordPress може обслуговувати автентифіковані REST-запити.

Рішення: Якщо редактор все ще падає, але це працює — ймовірно проблема в cookie+nonce або CORS, а не «REST не працює».

Завдання 16: Виявлення циклів редиректів і конфліктів канонізації

cr0x@server:~$ curl -sS -I -L -o /dev/null -w '%{url_effective} %{http_code}\n' http://example.com/wp-json/
https://www.example.com/wp-json/ 200

Що означає вивід: HTTP був перенаправлений на HTTPS і www, потім успішно відповів.

Рішення: Якщо бачите повторювані редиректи або він завершується на не-JSON локації — виправте siteurl/home, заголовки проксі (X-Forwarded-Proto) і правила канонізації на edge і у WordPress.

Завдання 17: Перевірте заголовки CORS для headless фронтендів

cr0x@server:~$ curl -sS -D- -o /dev/null -X OPTIONS \
  -H 'Origin: https://app.example.net' \
  -H 'Access-Control-Request-Method: POST' \
  https://example.com/wp-json/wp/v2/posts | egrep -i 'http/|access-control'
HTTP/2 403

Що означає вивід: OPTIONS preflight блокується. Багато WAF-ів вважають OPTIONS підозрілим. Браузери відмовляться від фактичного запиту, якщо preflight не проходить.

Рішення: Дозвольте OPTIONS до /wp-json/* на edge і налаштуйте WordPress/CORS-плагін ретельно. Також переконайтеся, що ви випадково не вимагаєте автентифікацію для preflight.

Завдання 18: Перевірте насичення PHP-FPM (REST «працює», поки не перестане)

cr0x@server:~$ sudo ss -s | sed -n '1,20p'
Total: 693
TCP:   41 (estab 18, closed 12, orphaned 0, synrecv 0, timewait 12/0), ports 0

Transport Total     IP        IPv6
RAW       0         0         0
UDP       9         7         2
TCP       29        18        11
INET      38        25        13
FRAG      0         0         0

cr0x@server:~$ sudo systemctl status php8.2-fpm --no-pager | sed -n '1,20p'
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled)
     Active: active (running) since Sat 2025-12-27 09:40:12 UTC; 32min ago
   Main PID: 1021 (php-fpm8.2)
     Status: "Processes active: 28, idle: 0, Requests: 1827, slow: 12"

Що означає вивід: Нуль простих воркерів і зростання повільних запитів означає, що REST API може падати під навантаженням з 502/504, особливо для автентифікованих кінцевих точок.

Рішення: Збільшіть потужність FPM (в межах доступної ОЗП), зменшіть витратні плагіни, додайте кешування для публічних кінцевих точок і припиніть дозволяти ботам бити по /wp-json.

Що зазвичай ламає REST (реальні режими відмов)

1) Перезаписи та пермалінки: нудна основа

Якщо /wp-json/ повертає 404, але index.php?rest_route=/ працює, ваші перезаписи зламані. Зазвичай це одне з:

  • відключений Apache mod_rewrite.
  • AllowOverride None блокує .htaccess.
  • відсутній fallback try_files ... /index.php в Nginx.
  • правила мультисайту не відповідають фактичній структурі директорій.
  • пермалінки перемикали, але правила не скинуто.

Порада: якщо ви на Nginx і розраховуєте на «автоматичні» перезаписи WordPress — ви вже торгуєте з фізикою. Покладіть правильні правила Nginx у систему контролю версій і перестаньте вважати, що адмінка керує вашим вебсервером.

2) Зворотні проксі та «допоміжні» редиректи

REST чутливий до схеми/хоста, бо автентифікація використовує cookies і nonce, прив’язані до origin. Якщо проксі завершує TLS, але WordPress думає, що працює на HTTP, ви побачите:

  • цикли редиректів
  • cookies встановлені для невірного домену
  • провали валідації nonce (часто показуються як 401)

Виправлення зазвичай включають налаштування правильних пересланих заголовків і переконання, що WordPress їх поважає (або коректне встановлення home/siteurl плюс конфіг, що враховує проксі).

3) WAF і захист від ботів, що блокують /wp-json

Шари безпеки люблять блокувати JSON-API, бо атакувальники теж їх люблять. На жаль, і ваш редактор їх теж любить.

Типові тригери WAF:

  • POST-тіла, що виглядають як HTML або містять <script> у легітимному контенті.
  • Повторювані запити від залогінених користувачів (Gutenberg дуже балакучий).
  • OPTIONS preflight для CORS.
  • Лімітування, що не відрізняє бота від редактора.

Виправляйте звужуючи винятки: дозволяйте конкретні методи та шляхи, логгайте агресивно та тримайте радіус ураження малим. «Вимкнути WAF» — не виправлення; це лист відмови.

4) Шари кешування, що трактують REST як статичний контент

Публічні ендпоінти можна кешувати обережно. Автентифіковані ендпоінти зазвичай не повинні кешуватися на edge. Коли кеши помиляються, ви бачите:

  • користувачі бачать дані інших (рідко, але катастрофічно)
  • застарілі nonce і випадкові 401
  • випадкові HTML-відповіді, бо кеш зберіг блок-сторінку

Практичне правило: ніколи не кешуйте запити з cookie на edge, якщо ви не знаєте точно, що робите і не можете довести ізоляцію ключів кешу.

5) Конфлікти плагінів: реєстрація маршрутів і фільтрація запитів

Плагіни можуть ламати REST шляхом:

  • некоректної реєстрації маршрутів (конфлікти неймспейсів, невірні permission callbacks)
  • фільтрації rest_authentication_errors та безумовного повернення помилок
  • виведення пробілів/повідомлень, які псують JSON
  • зміни content-type або буферизації виводу

Якщо відключення одного плагіна вирішує проблему — у вас є винуватець. Якщо відключення всіх плагінів вирішує — це плагін, але не сказано який. Ізолюйте систематично.

6) Автентифікація: cookies, nonce і безліч шляхів їх псування

Gutenberg і адмін-екрани часто використовують cookie-автентифікацію з nonce. Це означає, що браузер повинен:

  • надсилати правильні cookies для правильного домену/шляху
  • надсилати дійсний nonce у заголовку (X-WP-Nonce)
  • не блокуватися політиками SameSite або через невідповідність доменів

Коли це не працює, сам REST API може бути у порядку, але редактор кричатиме. Виправляють це вирівнюючи домени, схеми та поведінку cookie — не «переінсталюючи WordPress».

7) Надійність бекенду: фатали PHP, таймаути БД, проблеми зі зберіганням

REST-запити виконують шляхи коду WordPress. Вони звертаються до бази. Вони читають/пишуть опції. Вони можуть генерувати мініатюри. Вони можуть звертатися до зовнішніх API. Якщо ваше сховище повільне або БД нещасна, REST-ендпоінти впадуть першими, бо їх постійно викликають сучасні функції WordPress.

Як порада інженера зі зберігання: «випадкові» відмови REST під навантаженням часто корелюють зі сплесками затримки введення/виведення, особливо на шаред-хостингу або недомірних мережевих дисках. Перевірте I/O wait і здоров’я БД, перш ніж звинувачувати REST у «схильності до збоїв».

Жарт #2: Якщо ваш REST API ламається тільки по понеділках, він не одержимий — це ваш графік деплоїв у масці.

Три корпоративні міні-історії з практики

Міні-історія 1: Інцидент через неправильне припущення

Середня компанія запустила WordPress за зворотним проксі і CDN. Вони розгорнули нову headless-лендінг-сторінку, яка забирала записи через REST. У staging все працювало. У production редактор перестав публікувати, а headless-сторінка інколи повертала 401. Усі звинувачували «WordPress, яким він є».

Неправильне припущення було просте: «Якщо сайт завантажується, API має бути в порядку». Головна сторінка була закешована на CDN. REST-запити не були — хоча інколи вони кешувались, бо CDN мав загальне правило кешувати «всі GET-запити». Публічні REST GET кешувалися. Автентифіковані GET теж кешувалися, бо ключ кешу ігнорував cookies заради продуктивності.

Наслідком була періодична плутанина: відповідь одного редактора могла бути віддана іншому (іноді блокувалася перевірками прав, іноді ні). Команда не помітила витоку даних, але помітила зламані сесії і помилки nonce, бо кешовані відповіді не відповідали очікуванням браузера.

Виправлення не було героїчним. Вони змінили політику CDN: обходити кеш для будь-якого запиту з Cookie і для будь-якого шляху під /wp-json/, якщо явно не дозволено. Потім вони дозволили у whitelist лише кілька публічних кінцевих точок з безпечним ключем кешу і коротким TTL. REST стабілізувався миттєво.

Висновок: ніколи не припускайте, що «веб працює» означає «API працює», особливо коли задіяне кешування. Ваша головна сторінка — брехун; curl — чесний.

Міні-історія 2: Оптимізація, що відбилася назад

Корпоративна маркетинг-команда захотіла швидший TTFB. Інженер увімкнув агресивну оптимізацію HTML і компресію відповідей на зворотному проксі. Він також увімкнув набір правил «зміцнення безпеки», щоб блокувати «підозрілі рядки запиту».

Продуктивність публічного сайту покращилася. Потім Gutenberg почав падати при завантаженні зображень і оновленнях постів. Панель Site Health повідомляла про помилки REST API. Розробники почали ганяти фейкові конфлікти плагінів.

Справжня проблема: правило оптимізації проксі буферизувало і переписувало відповіді та встановило маленький client_max_body_size. Завантаження медіа через REST супроводжувались 413. Одночасно правило «підозрілий рядок запиту» відмічало шаблони rest_route= і блокувало fallback-запити, які використовували деякі клієнти й плагіни.

Виправлення було банально простим: підняти ліміти розміру тіла в релевантних location-блоках, вимкнути переписування для JSON-відповідей і відрегулювати правила WAF для відомих REST-маршрутів. Також вони додали моніторинг конкретно для статус-кодів /wp-json/, щоб ловити регресії раніше, ніж помітила маркетинг-команда.

Висновок: оптимізації дозволені. Але вони потребують allowlist-ментальності для API. Якщо ваш проксі модифікує payload, ви виконуєте роботу додатка без тестів додатка.

Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію

Глобальна організація керувала кількома інстансами WordPress з ідентичною інфраструктурою-as-code для Nginx і PHP-FPM. Їхня SRE-команда запровадила одну нудну політику: кожна конфігураційна зміна мала канарку, і кожна канарка мала синтетичну перевірку, яка запитувала /wp-json/, публічний ендпоінт і автентифікований ендпоінт.

Одного тижня незначна зміна Nginx, спрямована на посилення безпеки, випадково видалила fallback try_files і перетворила невідомі шляхи на 404. Публічний сайт все ще працював, бо більшість сторінок кешувалися і загальні маршрути існували. Але REST-запити почали падати миттєво на канарці.

Синтетичні перевірки спіймали це за кілька хвилин. Вони відкотили зміни до повного розгортання. Жодних звернень клієнтів. Жодних панічних розкопок в Slack. Лише чистий відкат і невеликий постмортем.

Висновок: «нудні» практики — канарки, синтетичні перевірки і конфіг у версійному контролі — рятують вас від хитрощів. REST — ідеальна ціль для канарки, бо швидко проходить маршрутизацію, PHP і логіку додатка.

Типові помилки: симптом → корінна причина → виправлення

Цей розділ призначений для використання під тиском. Знайдіть ваш симптом і зробіть виправлення. Не дискутуйте філософію під час простою.

1) WordPress каже «REST API encountered an error», і /wp-json повертає HTML

  • Симптом: content-type: text/html, можливо сторінка входу або сторінка блокування.
  • Корінна причина: WAF/CDN блок, редирект на вхід або кешований шаблон помилки.
  • Виправлення: Обійдіть edge до origin і порівняйте. Вимкніть кешування для /wp-json. Додайте правила дозволу WAF для REST-шляхів/методів. Підтвердіть, що для API маршрутів не застосовується редирект на вхід.

2) /wp-json працює, але автентифіковані ендпоінти повертають 401 в редакторі

  • Симптом: Публічні ендпоінти OK; дії в редакторі падають; випадкові «nonce invalid».
  • Корінна причина: Невідповідність домену/схеми cookie, проблеми SameSite cookie, проксі не надсилає правильний X-Forwarded-Proto або кешування nonce.
  • Виправлення: Вирівняйте home і siteurl. Виправте заголовки проксі і канонічні редиректи. Переконайтеся, що автентифіковані REST-запити ніде не кешуються.

3) /wp-json повертає 404, але index.php?rest_route працює

  • Симптом: Шлях перезапису не працює, прямий запит працює.
  • Корінна причина: Неправильна конфігурація перезапису Nginx/Apache, .htaccess ігнорується або відсутній try_files fallback.
  • Виправлення: Виправте конфігурацію сервера. Скиньте перезаписи. Повторно тестуйте обидві кінцеві точки до ідентичної поведінки.

4) REST-запити повертають 403 тільки для POST/PUT/DELETE

  • Симптом: GET працює; записування блокується.
  • Корінна причина: Правило WAF блокує методи, false positive мод_security CRS або обмеження методів на проксі.
  • Виправлення: Перегляньте логи WAF за ID правила і налаштуйте винятки вузько для /wp-json. Переконайтеся, що проксі дозволяє ці методи до origin.

5) REST повертає 500 періодично, у логах видно фатали PHP

  • Симптом: 500/502 з трасуванням у логах PHP.
  • Корінна причина: Баг плагіна/теми або несумісність версії PHP.
  • Виправлення: Відкотіть зміну, що внесла фатали. Запатчіть плагін. Додайте автоматизовані тести або хоча б синтетичні REST-перевірки в pipeline деплою.

6) REST повільний; іноді 504 Gateway Timeout

  • Симптом: Довгі відповіді, потім таймаути під навантаженням.
  • Корінна причина: Вичерпання воркерів PHP-FPM, контенція БД, повільне сховище, зовнішні API у шляху запиту.
  • Виправлення: Профілюйте повільні запити; обережно збільшіть потужність FPM; оптимізуйте БД і object cache; додайте таймаути/схему переключення для зовнішніх викликів; блокуй аб’юз клієнтів.

7) Помилки CORS у консолі браузера, curl працює

  • Симптом: Браузер блокує запити; curl успішний.
  • Корінна причина: Відсутні/заблоковані заголовки CORS, OPTIONS блокується, невірні заголовки Origin.
  • Виправлення: Дозвольте OPTIONS через WAF/проксі і налаштуйте коректні Access-Control-Allow-Origin та пов’язані заголовки, бажано з allowlist-ом.

Контрольні списки / покроковий план

Контрольний список A: У вас зараз помилка REST

  1. Запустіть curl до /wp-json/ і зафіксуйте статус, заголовки та тип тіла відповіді (JSON vs HTML).
  2. Запустіть curl до /index.php?rest_route=/ і порівняйте.
  3. Протестуйте з origin-хоста з заголовком Host:, щоб обійти edge.
  4. Якщо причетний edge: перевірте логи WAF/CDN на блокування, ліміти та обмеження методів.
  5. Якщо причетні перезаписи: перевірте try_files Nginx або AllowOverride/mod_rewrite Apache.
  6. Якщо причина в автентифікації: протестуйте Application Password; потім cookie+nonce-потоки редактора.
  7. Якщо 500/таймаут: перевірте логи PHP, насичення FPM, стан БД і останні деплои/зміни плагінів.

Контрольний список B: Запобігти наступному інциденту (операційна гігієна)

  1. Додайте синтетичні перевірки для /wp-json/, публічного ендпоінту і автентифікованого ендпоінту.
  2. Інструментуйте статус-коди для /wp-json в логах доступу і ставте алерти на сплески 4xx/5xx.
  3. Покладіть конфіги Nginx/Apache в контроль версій; пропускайте зміни через канарки.
  4. Ясно визначте політику кешування: які REST-ендпоінти кешуються і як будуються ключі кешу.
  5. Створіть процес винятків WAF: allowlist шляхів/методів, відстеження ID правил і огляди термінів дії.
  6. Тримайте оновлення плагінів у стадіях; моніторте синтетичні REST-перевірки після деплою.

Контрольний список C: Коли підозрюєте конфлікт плагіна

  1. Зробіть знімок списку активних плагінів.
  2. Вимикайте по одному ризикованому плагіну (безпека/кешування).
  3. Повторно тестуйте /wp-json/ і той маршрут, що падає.
  4. Коли працює — вмикайте інших по черзі, щоб ізолювати.
  5. Застосуйте конфігураційне виправлення або замініть плагін, якщо він не може співіснувати з вашими вимогами.

Цікаві факти та історія (коротко, корисний контекст)

  • Факт 1: WordPress REST API починався як feature-плагін перед злиттям у ядро, тому старі статті досі згадують «REST API plugin».
  • Факт 2: Базова кінцева точка /wp-json/ — це індексний документ — API «змістова частина», тому зламаний індекс часто означає проблему маршрутизації або блокування, а не «відсутні записи».
  • Факт 3: Gutenberg (блоковий редактор) сильно залежить від REST. Якщо REST нестабільний, редактор зазвичай перший починає скаржитися.
  • Факт 4: WordPress може обслуговувати REST через параметр запиту (rest_route), що робить його відмінним інструментом для розрізнення проблем перезаписів від проблем додатка.
  • Факт 5: Багато продуктів безпеки історично трактували JSON-ендпоінти як «поверхню API» і за замовчуванням включали жорсткішу інспекцію, через що false positive часто зосереджуються навколо /wp-json.
  • Факт 6: REST-маршрути реєструються кодом під час виконання. Якщо плагін не завантажився (фатальна помилка), цілі неймспейси маршрутів можуть зникнути, перетворивши очікувані 200 на 404.
  • Факт 7: Автентифікація WordPress для браузерних REST-викликів часто використовує nonce замість Basic Auth; nonce чутливі до часу і легко ламаються кешуванням або зсувом часу.
  • Факт 8: Історично деякі хости і плагіни блокували шляхи /wp-json/wp/v2/users для зменшення ризику перелічення користувачів, інколи блокуючи занадто широко і ламаючи легітимні дії адміністратора.
  • Факт 9: Політики кешування CDN, що ігнорують cookies, можуть спричинити витік API-відповідей між сесіями — рідко, але траплялося достатньо, щоб досвідчені SRE нервувалися щодо цього.

Питання й відповіді

1) Як зрозуміти, чи WordPress REST впав чи лише редактор?

Запустіть curl -D- https://example.com/wp-json/. Якщо це 200 з JSON — REST працює. Якщо редактор не працює, зосередьтеся на автентифікації/nonce/cookies і кешуванні.

2) Чому /wp-json працює, але /wp-json/wp/v2/posts падає?

Індекс може завантажитись, тоді як конкретні маршрути падають через код плагіна/теми, permission callbacks або проблеми реєстрації маршруту. Перевірте логи PHP і відключайте плагіни для ізоляції.

3) Який найшвидший тест перезаписів?

Порівняйте /wp-json/ з /index.php?rest_route=/. Якщо працює лише другий — проблема в перезаписах вебсервера.

4) Чому я отримую 401 Unauthorized хоча в адмінці я залогінений?

Зазвичай це невідповідність cookie/nonce через домен або схему (www vs non-www, http vs https), політику SameSite cookie або проксі, що неправильно повідомляє HTTPS.

5) Як зрозуміти, чи WAF блокує REST?

Шукайте 403 з HTML-блок-сторінками, заголовки CDN/WAF або блокування лише для POST/OPTIONS. Обійдіть edge до origin; якщо origin працює — це WAF/CDN.

6) Чи можу я кешувати відповіді REST API?

Так, вибірково. Кешуйте лише справді публічні, неперсоналізовані ендпоінти. Ніколи не кешуйте запити з cookie на edge, якщо не можете довести безпеку ключів кешу і ізоляцію.

7) Чому я бачу помилки CORS, але curl працює?

Браузери застосовують CORS і часто виконують preflight OPTIONS. Якщо OPTIONS блокується або CORS-заголовки неправильні, браузер відмовляє. Curl на це не зважає.

8) Чи завжди вимкнення плагінів доводить, що проблема в плагіні?

Вимкнення доводить взаємодію, але не винуватість. Плагін може лише спровокувати правило проксі/WAF або виявити приховану проблему конфігурації. Використовуйте це, щоб звузити сферу, а потім знайдіть справжню корінну причину.

9) Який найбезпечніший метод автентифікації для сервер‑до‑сервер REST‑викликів?

Application Passwords зазвичай найменш болісні в ядрі WordPress. Використовуйте HTTPS, обмежуйте права, ротуйте облікові дані і моніторте на зловживання.

10) Чому REST падає тільки під навантаженням?

Тому що під навантаженням ви досягаєте лімітів: воркери PHP-FPM, з’єднання БД, затримки I/O або лімітування. REST-ендпоінти балакучі і швидко підсилюють вузькі місця.

Висновок: наступні кроки, що дійсно зменшують рецидиви

Якщо зробите лише кілька дій з цього списку, зробіть ці:

  1. Зробіть /wp-json/ спостережуваним. Додайте синтетичні перевірки та алерти на статус-коди і затримки. REST — це канарка для сучасного WordPress.
  2. Розділіть маршрутизацію, автентифікацію та здоров’я бекенду. Використовуйте тест rest_route, щоб довести перезаписи; потім тестуйте публічні ендпоінти, потім автентифіковані.
  3. Припиніть дозволяти проміжним елементам імпровізувати. Явно визначайте кешування і WAF‑поведінку для /wp-json. Default‑deny — ок; default‑surprise — ні.
  4. Версифікуйте конфігурацію вашого вебсерверу. Якщо доступність REST залежить від одноразового фрагмента Nginx, вставленого три роки тому — у вас не конфіг, а фольклор.

Тепер зробіть негламурну річ: виконайте перші три завдання, запишіть спостережувану поведінку і слідуйте шару, куди вказує реальність. Збої WordPress REST рідко містять таємницю. Вони просто розподілені по стількох компонентах, що люди плутають «складно» з «незрозуміло».

← Попередня
Офісний VPN: дозвіл доступу лише до одного сервера/порту (найменші привілеї)
Наступна →
Налаштування кешування WordPress і Cloudflare, які не порушують роботу wp-admin

Залишити коментар