У розробці веб-служби RESTful за допомогою HATEOAS, якими є плюси та мінуси показу посилання як повної URL-адреси (" http: // server: port / application / customers / 1234 ") проти просто шляху ("/ application / клієнти / 1234 ")?
У розробці веб-служби RESTful за допомогою HATEOAS, якими є плюси та мінуси показу посилання як повної URL-адреси (" http: // server: port / application / customers / 1234 ") проти просто шляху ("/ application / клієнти / 1234 ")?
Відповіді:
Існує тонка концептуальна двозначність, коли люди кажуть "відносний URI".
За визначенням RFC3986 , загальний URI містить:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
Хитра річ у тому, що коли схема та повноваження опущені, сама частина "шляху" може бути як абсолютним шляхом (починається з /
), так і відносним шляхом, що не має коренів. Приклади:
"http://example.com:8042/over/there?name=ferret"
/over/there
here
або ./here
або ../here
або тощо.Отже, якщо запитання було "чи повинен сервер виробляти відносний шлях у спокійній відповіді", відповідь "Ні", а детальна причина доступна тут . Я думаю, що більшість людей (включаючи мене) проти "відносного URI" насправді проти "відносного шляху".
І на практиці більшість платформ MVC на стороні сервера можуть легко генерувати відносний URI з абсолютним шляхом, таким як /absolute/path/to/the/controller
, і виникає питання "чи повинна серверна реалізація ставити префікс scheme://hostname:port
перед абсолютним шляхом". Як питання ОП. Я не зовсім впевнений у цьому.
З одного боку, я все ще думаю, що рекомендується сервер, що повертає повний uri. Однак сервер ніколи неhostname:port
повинен жорстко кодувати річ всередині вихідного коду, як це (інакше я б віддав перевагу відносному uri з абсолютним шляхом). Рішення полягає на стороні сервера, завжди отримуючи цей префікс із заголовка "Хост" запиту HTTP. Не впевнений, чи працює це в будь-яких ситуаціях.
З іншого боку, для клієнта здається не дуже клопітким об'єднати http://example.com:8042
і абсолютний шлях. Зрештою, клієнт вже знає цю схему та доменне ім'я, коли надсилає запит на сервер, чи не так?
Загалом, я б сказав, рекомендую використовувати абсолютний URI, можливо, відновлення до відносного URI з абсолютним шляхом, ніколи не використовувати відносний шлях .
Це залежить від того, хто пише код клієнта. Якщо ви пишете клієнт і сервер, це не має великої різниці. Ви будете страждати від створення URL-адрес на клієнті або на сервері.
Однак, якщо ви створюєте сервер, і ви очікуєте, що інші люди напишуть код клієнта, вони будуть любити вас набагато більше, якщо ви надасте повні URI. Вирішення відносних URI може бути дещо складним. Спочатку спосіб їх вирішення залежить від типу носія, що повертається. Html має базовий тег, Xml може мати xml: базові теги у кожному вкладеному елементі, канали Atom можуть мати базу в стрічці та іншу базу у вмісті. Якщо ви не надаєте своєму клієнтові явної інформації про базовий URI, тоді він повинен отримати базовий URI з URI запиту або, можливо, із заголовка Content-Location! І стежте за цією косою рисою. Базовий URI визначається, ігноруючи всі символи праворуч від останньої риски. Це означає, що кінцева коса риса зараз дуже важлива при вирішенні відносних URI.
Єдине інше питання, яке вимагає невеликої згадки - це розмір документа. Якщо ви повертаєте великий список елементів, де кожен елемент може мати кілька посилань, використання абсолютних URL-адрес може додати значну кількість байтів до вашої сутності, якщо ви не стискаєте сутність. Це питання про ефективність, і вам потрібно вирішити, чи є воно суттєвим для кожного конкретного випадку.
У міру масштабування вашої програми, можливо, ви захочете виконати балансування навантаження, відмову і т. Д. Якщо ви повернете абсолютні URI, тоді ваші програми на стороні клієнта будуть слідувати вашій конфігурації серверів.
/xxx/yyy...
), а не як повний URI (наприклад http://api.example.com/xxx/yyy...
).
Використовуючи трихотомію RayLou, моя організація обрала перевагу (2). Основною причиною є уникнення атак XSS (Cross-Site Scripting). Проблема полягає в тому, що якщо зловмисник може внести власний корінь URL-адреси у відповідь, що повертається із сервера, тоді наступні запити користувачів (наприклад, запит автентифікації з іменем користувача та паролем) можуть бути перенаправлені на власний сервер зловмисника *.
Деякі порушували проблему можливості перенаправляти запити на інші сервери для балансування навантаження, але (хоча це не є моєю компетенцією) я б поклався на заклад, що є кращі способи ввімкнути балансування навантаження без необхідності явного перенаправлення клієнтів на різні господарі.
* будь ласка, дайте мені знати, якщо в цій лінії міркувань є якісь недоліки. Мета, звичайно, не запобігти всім атакам, а хоча б один шлях атаки.
Ви завжди повинні використовувати повну URL-адресу. Він діє як унікальний ідентифікатор ресурсу, оскільки всі URL-адреси повинні бути унікальними.
Я також стверджую, що ви повинні бути послідовними. Оскільки HTTP-заголовок Location очікує повної URL-адреси на основі специфікації HTTP, повна URL-адреса надсилається клієнту в заголовку Location, коли створюється новий ресурс. Було б дивним для вас вказати повну URL-адресу в заголовку Розташування, а потім відносні URI у посиланнях у тілі відповіді.
Location
дає приклад специфікації заголовка - абсолютний URI, який не містить схеми URI або мережевого розташування сервера. Хоча посилання та ідентифікатори часто поєднуються, це не одне і те ж - у першого є контекст, у другого немає.
Важливим фактором, що враховує великі результати API, є додаткові накладні витрати на мережу, які включають повний URI повторно. Вірте чи ні, але gzip не цілком вирішує цю проблему (не впевнений, чому). Ми були вражені тим, скільки місця зайняв повний URI, коли в результаті були сотні посилань.
Одним недоліком використання абсолютних URI є те, що api не можна проксі-сервером.
Візьми назад ... неправда. Вам слід вибрати повну URL-адресу, включаючи домен.
Щодо плюсів, я бачу зменшення байтів, що передаються за рахунок додаткової обробки, необхідної клієнту для (абсолютного) шляху. Якщо ви відчайдушно бажаєте зберегти кожен байт, навіть після спроби кодування вмісту як gzip, правильного використання заголовків кешування, використання етагів та умовних запитів на клієнті, то це може знадобитися зрештою, але я очікую набагато більшої віддачі від твої зусилля були ще.
Щодо мінусів, я бачу втрату контролю над тим, як ви можете направляти потік клієнтів між ресурсами в майбутньому (балансування навантаження, A / B тестування, ...), і я вважаю це поганою практикою щодо управління Інтернетом API. Надана вами URL-адреса більше не є непрозорою для клієнта (див. Аксіоми веб-архітектури Тіма Бернерса-Лі щодо непрозорості URI ). Зрештою, ви стаєте відповідальними за те, щоб клієнти були щасливими щодо їх творчого використання вашого API, навіть якщо це стосується лише структури вашого простору URL. Якщо вам коли-небудь доведеться дозволити чітко визначену модифікацію URL-адреси, розгляньте можливість використання шаблонів URI, як вони використовуються в мові додатків гіпертексту .