При разработке RESTful веб-сервиса, является ли уместным включать тело запроса с HTTP GET запросами, и какие потенциальные проблемы могут возникнуть у HTTP-клиентов при использовании тел запросов в GET запросах?
Я проектирую новый RESTful веб-сервис, где клиентам необходимо запрашивать содержимое сущностей. В настоящее время они могут добавлять параметры, такие как критерии сортировки, через строку запроса. Однако я рассматриваю возможность указания параметров в теле запроса вместо этого, поскольку HTTP/1.1 прямо не запрещает этот подход. Это позволило бы реализовать более сложные спецификации параметров, например, на основе XML.
Какие потенциальные проблемы совместимости или ограничения могут возникать у HTTP-клиентов при отправке тел запросов вместе с GET запросами?
HTTP GET запросы технически могут включать тело запроса в соответствии со спецификацией HTTP/1.1, но это настоятельно не рекомендуется из-за проблем совместимости и нарушает принципы REST. Большинство HTTP-клиентов, включая Fetch API, XMLHttpRequest и Angular HttpClient, явно запрещают отправку тел с GET запросами, что может вызвать серьезные проблемы интероперабельности на разных платформах и в браузерах.
Содержание
- Контекст спецификации HTTP
- Принципы проектирования REST API
- Проблемы реализации на стороне клиента
- Проблемы совместимости на разных платформах
- Альтернативные подходы для сложных параметров
- Рекомендации по лучшим практикам
Контекст спецификации HTTP
Спецификация HTTP/1.1 предоставляет нюансированные рекомендации относительно тел GET запросов. Согласно RFC 7231 §4.3.1, полезная нагрузка в GET запросе имеет “неопределенную семантику”. Это означает, что хотя спецификация не явно запрещает тела в GET запросах, она также не придает им какого-либо значения.
“Полезная нагрузка в сообщении GET запроса имеет неопределенную семантику; отправка тела запроса в GET запросе может привести к тому, что некоторые существующие реализации отклонят запрос.”
Эта неоднозначность создает несколько проблем. Хотя технически возможно отправлять тело с GET запросом, серверы не должны рассматривать тело как имеющее какую-либо семантическую ценность, что в первую очередь лишает смысла включение сложных параметров. Спецификация уточняет, что метод запроса определяет, разрешено ли использование тела запроса, и GET относится к методам, где семантика ограничена.
Принципы проектирования REST API
Принципы проектирования RESTful API настоятельно не рекомендуют использовать тела запросов с методами GET. Согласно руководству по проектированию API от Speakeasy, “использование тела запроса для HTTP метода GET очень осуждается, но ожидается для POST, PUT, PATCH и QUERY.”
Основной принцип REST, регулирующий это, - идемпотентность и безопасность операций GET:
- GET запросы должны быть безопасными (не изменять состояние сервера)
- GET запросы должны быть идемпотентными (несколько идентичных запросов должны иметь тот же эффект)
- GET запросы должны извлекать ресурсы, а не отправлять данные для обработки
Когда вы включаете тело запроса в GET запрос, вы по сути используете GET для обработки данных, а не извлечения ресурсов, что нарушает эти фундаментальные принципы REST. Руководства по RESTful API от Zalando далее подчеркивают, что POST следует использовать для сценариев, которые не могут быть достаточно охвачены другими методами.
Проблемы реализации на стороне клиента
Современные HTTP-клиенты имеют разный уровень поддержки GET запросов с телами, но большинство либо явно запрещают это, либо ведут себя непредсказуемо:
Fetch API: Документация MDN четко гласит: “Вы не можете включать тело с GET запросами.” Это сознательный дизайн-выбор, который соответствует принципам REST и предотвращает путаницу.
XMLHttpRequest: Согласно нескольким источникам, XMLHttpRequest не позволяет использовать тела запросов для GET или HEAD запросов. Этот деталь реализации влияет на многие JavaScript библиотеки, использующие XHR под капотом.
Angular HttpClient: Как отмечается в обсуждениях на Stack Overflow, Angular не поддерживает передачу тела с GET запросом, и нет обходного пути, поскольку это ограничение исходит из базового API XMLHttpRequest.
Axios: При работе в браузерных средах Axios по умолчанию использует XMLHttpRequest, который не позволяет использовать тела в GET. Хотя среда Node.js может обрабатывать это иначе, это создает несоответствия между средами.
Эти различия в реализации означают, что любой веб-сервис, ожидающий GET запросов с телами, не будет работать во многих распространенных клиентских средах.
Проблемы совместимости на разных платформах
Даже за пределами JavaScript клиентов, различные реализации HTTP обрабатывают GET запросы с телами непоследовательно:
Несоответствия в браузерах: Разные браузеры могут обрабатывать GET запросы с телами по-разному, некоторые разрешают это, а другие полностью отклоняют. Это создает кошмар совместимости между браузерами.
Вариации реализации серверов: Некоторые серверы могут полностью отклонять GET запросы с телами, в то время как другие могут принимать их, но игнорировать содержимое тела. Эта непредсказуемость делает невозможным полагаться на последовательное поведение.
Обработка ошибок: Клиенты, пытающиеся отправлять GET запросы с телами, могут столкнуться с различными кодами ошибок:
- 411 Length Required: Когда серверы ожидают заголовок Content-Length, который обычно не включается в GET запросы
- 400 Bad Request: Когда серверы явно отклоняют GET методы с телами
- Ошибки подключения: Когда реализации клиентов просто не поддерживают эту операцию
Проблемы CORS: Правила Cross-Origin Resource Sharing могут усугубить эти проблемы, особенно при работе с разными политиками безопасности браузеров.
Центр архитектуры Microsoft Azure предупреждает, что хотя технически можно проектировать API определенными способами, следует обеспечить совместимость между разными клиентскими реализациями.
Альтернативные подходы для сложных параметров
Вместо использования GET с телами запроса, рассмотрите эти соответствующие REST альтернативы:
Параметры строки запроса: Для критериев сортировки и других простых параметров строка запроса остается наиболее подходящим местом. Хотя URL имеют ограничения по длине (обычно 2048 символа), большинство современных серверов обрабатывают гораздо более длинные URL.
POST для операций поиска: Когда вам нужны сложные спецификации параметров, особенно на основе XML, POST является подходящим методом. Операция поиска сама становится ресурсом, над которым производится действие.
HTTP QUERY метод: Некоторые API реализуют пользовательский QUERY метод, который находится между GET и POST, предоставляя семантически верный способ отправки сложных параметров при соблюдении принципов RESTful проектирования.
Ориентированное на ресурсы проектирование: Как предлагает restfulapi.net, проектируйте ваши URI для представления ресурсов, а не действий. Вместо сложных параметров создавайте подходящие конечные точки ресурсов.
Руководство по проектированию API от Moesif предоставляет отличные примеры, когда переходить от параметров строки запроса к POST на основе сложности параметров.
Рекомендации по лучшим практикам
На основе результатов исследования, вот ключевые рекомендации для вашего RESTful веб-сервиса:
-
Избегайте GET с телами: Придерживайтесь параметров строки запроса для GET запросов, даже если спецификация HTTP технически разрешает тела.
-
Используйте POST для сложных данных: Когда клиентам нужно отправлять сложные спецификации параметров, такие как XML, используйте POST запросы с соответствующими типами медиа.
-
Рассмотрите версионирование API: Как отмечено в руководствах по RESTful API от ONAP, обеспечьте обратную совместимость изменений вашего API, реализовав правильное версионирование.
-
Документируйте ограничения: Если вы абсолютно должны поддерживать GET с телами (не рекомендуется), четко документируйте это и предоставьте клиентские обходные пути.
-
Тестируйте на разных клиентах: Тщательно тестируйте вашу реализацию API на разных HTTP-клиентах, в браузерах и на платформах для обеспечения последовательного поведения.
-
Соблюдайте соответствие стандартам: Придерживайтесь стандартов RFC и общепринятых практик REST для обеспечения максимальной совместимости и принятия.
Статья Baeldung по компьютерным наукам предоставляет исчерпывающее техническое объяснение, почему GET запросы не должны иметь тел, подчеркивая как соответствие спецификациям, так и практические проблемы реализации.
Заключение
Хотя HTTP/1.1 не явно запрещает тела запросов в GET запросах, делать это неуместно для RESTful веб-сервисов из-за множества проблем совместимости. Большинство HTTP-клиентов предотвращают отправку тел с GET запросами, создавая значительные проблемы интероперабельности на разных платформах и в браузерах. Вместо того чтобы заставлять сложные параметры помещаться в тела GET запросов, используйте строки запросов для простых параметров и POST запросы для сложных спецификаций данных. Этот подход поддерживает принципы REST, обеспечивает максимальную совместимость и следует установленным лучшим практикам проектирования API, что сделает ваш веб-сервис более надежным и легким для использования в разных клиентских средах.
Источники
- HTTP GET with request body - Stack Overflow
- Request Body Best Practices in REST API Design | Speakeasy
- An Ultimate Guide on HTTP GET with Request Body
- Why an HTTP Get Request Shouldn’t Have a Body | Baeldung
- HTTP GET with Request body - Guidelines | TheCodeBuzz
- Best practices for REST API design - Stack Overflow
- Using the Fetch API - MDN
- XMLHttpRequest doesn’t allow request body for GET or HEAD · GitHub Issue
- REST API HTTP GET with Body - Stack Overflow
- Web API Design Best Practices - Azure Architecture Center