Пилим мы REST-сервисы для проекта. Стараемся следовать рекоммендациям для RESTful-архитектур, но иногда не получается. Вот, например, намедни коллега добавила метод с такой сигнатурой:
[HttpPost]
[Route("ValueSet/$expand")]
public FHIR.Model.Bundle GetValueSetMembersByOIDs(IEnumerable<string> oids)
На что я ей заметил, что метод, запрашивающий данные, должен использовать GET-запрос, а не POST. Коллега не соглашается, заявляет, мол, "я много раз так делала и всё нормально".
Вопрос — а допустимы ли такие фокусы в правильных REST-сервисах? Ну т.е. мне вот с одной стороны бросается в глаза такой косяк, но в то же время в описаниях REST-архитектур я не смог найти запрета на использование POST запросов вместо GET, для запроса данных.
Далее.. позвал я ихнего техлида и он мне пояснил причину такого кода — в кач-ве параметра к запросу передаётся массив идентификаторов. Каждый идентификатор — около 30 символов. Если передавать их как параметры GET-запроса, то легко массив из 60 идентификаторов займёт уже пару килобайт и они не уверены, не превысит ли это лимитов длины HTTP-запроса.
Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
Посоветуйте. Кто-нибудь наверняка ведь сталкивался с ситуацией, когда для запроса данных нужно передать несколько десятков параметров. Может какие-то примеры есть среди общеизвестных REST-сервисов?
Здравствуйте, Artem Korneev, Вы писали:
AK>Вопрос — а допустимы ли такие фокусы в правильных REST-сервисах? Ну т.е. мне вот с одной стороны бросается в глаза такой косяк, но в то же время в описаниях REST-архитектур я не смог найти запрета на использование POST запросов вместо GET, для запроса данных.
Учитывая все несовершенсво http-протокола — да. Если url может стать больше 2048 символов,
то неважно передаем мы массив или просто несколько параметров — нам надо юзать post.
Вот напр. если имя пользователя может превышать 1000символов и фамилия больше 1000
и вся остальная часть url=96 символов,
а нам надо сделать запрос ввида ?name=xxx&secondname=yyy — нужно делать только post запрос.
Если переделать http, для современного веба, то по правильному http get — надо убать вообще.
http post надо кешировать как сейчас http get,т.е. кешировать на время указанное сервером.
к http post добавить флаг (IsUrlCanBeWrittenByHands)- специально для броузеров и поисковиков,
указывающий что этот запрос надо показать пользователю ввиде читаемого url.
Підтримати Україну у боротьбі з країною-терористом.
Здравствуйте, Artem Korneev, Вы писали:
AK>Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
AK>Посоветуйте. Кто-нибудь наверняка ведь сталкивался с ситуацией, когда для запроса данных нужно передать несколько десятков параметров. Может какие-то примеры есть среди общеизвестных REST-сервисов?
Вообще говоря POST предназначен для созданиям объектов, т.е. он ради сайд эффектов. Особого криминала приспособить его для получения объектов в случае когда на серевер отправляется много параметров запроса тоже не вижу. Но желательно пересмотреть архитектуру, например когда надо сделать запросы по ид от 1 до 10, то оформлять в виде диапазонов и пихать в querystring. Тут можно поглядеть обсуждение.
Здравствуйте, #John, Вы писали:
J>Если переделать http, для современного веба, то по правильному http get — надо убать вообще. J>http post надо кешировать как сейчас http get,т.е. кешировать на время указанное сервером. J>к http post добавить флаг (IsUrlCanBeWrittenByHands)- специально для броузеров и поисковиков, J>указывающий что этот запрос надо показать пользователю ввиде читаемого url.
Вот есть операции, универсальные для любого объекта -- получить, добавить, удалить и изменить. Зачем нужно удалять операцию "получить", базовую по сути?
Здравствуйте, Artem Korneev, Вы писали:
AK>Пилим мы REST-сервисы для проекта. Стараемся следовать рекоммендациям для RESTful-архитектур, но иногда не получается. Вот, например, намедни коллега добавила метод с такой сигнатурой
Вообще, если речь идёт о fhir, то в его спецификации прямо все расписано, как делать запросы и каким http-методом, разве не?
Согласно спецификации можно и GET и POST
Здравствуйте, Sharov, Вы писали:
S>Вот есть операции, универсальные для любого объекта -- получить, добавить, удалить и изменить. Зачем нужно удалять операцию "получить", базовую по сути?
Потому что в современном вебе http исспользуется не по назначению.
Был когда-то создан ftp протокол для обмена документами через сервак
и у него были вполене логичные комманды для манипулирования доками на серваке.
Но прошлое некоторое время, люди увидели что ftp — это слишком сложно: надо скачать документ,
потом проанализировать его название, содержимое, подобрать программу которая бы понимала документ,
открыть, прочитать. Этим людям нравилось просматривать гипертекстовые страницы(html+теги), а не маны,
так что бы все ключевы слова были выделенны, заголовки подчеркнуты
и можно было быстро легко переходить на другие документы по ссылкам.
Прибилизительно в тоже время кто-то изобрел мышку и этим людям оч. понравилось ею клацать.
И они решили создать более простой протокол который работал бы как ftp, но только для просмотра документов
определенного типа: гипертекстовых страниц.
Прошло время(развивался html -добавлялись новые теги),
люди захотели вставлять смишнявки(картиночки) в html, а также изменять содержимое этих документов,
что бы люди всегда получали самую актуальную информацию: были добавлены методы put, delete,
а чтобы серевер могу выдержать нагружку в 10человек, при дорогущем итернете, был запилем метод post.
Но в то время, наши прадеды и не догадовали, во что может превратиться их безобидная шутка с гипертекстовыми страницам.
Однажды(будущий создатель js) подумал: пользователи загружают статические странички, но они такие скучные:
"Было бы классно, если бы картиночки прыгали вверх-вниз, а текст мигал."
"Вот круто разыграю своего товарища" — подумал человек и создал js.
Если бы созадатели html+http+js только знали что в начале 21го века, компьютеры сами будут скачивать не доверенный,
не проверенный, не лицинзионный исполняемый код(js), который будет манипулировать пользовательскими данными.
А на js будут создаваться полноценные ria single page mvpmvvmmvc приложения с rest-full серверной архитектурой,
они бы никогда, никогда так не шутили.
Если кратко:
http — не создавался под нужды современного веба, а был адаптирован из безобидной шутки.
Підтримати Україну у боротьбі з країною-терористом.
Здравствуйте, #John, Вы писали:
J>Здравствуйте, Sharov, Вы писали:
S>>Вот есть операции, универсальные для любого объекта -- получить, добавить, удалить и изменить. Зачем нужно удалять операцию "получить", базовую по сути? J>Потому что в современном вебе http исспользуется не по назначению.
J>Если кратко: J>http — не создавался под нужды современного веба, а был адаптирован из безобидной шутки.
REST как раз и призван это исправить и как-то упорядочить.
Здравствуйте, Artem Korneev, Вы писали:
AK>Посоветуйте. Кто-нибудь наверняка ведь сталкивался с ситуацией, когда для запроса данных нужно передать несколько десятков параметров. Может какие-то примеры есть среди общеизвестных REST-сервисов?
Передавал параметры в сервис в закодированном виде, по максимум убрав лишнюю информацию (там много чего можно сократить и выбросить). Аргумент у метода сервиса был простой строкой, которая парсилась и превращалась обратно в массив. Что-то вроде "<количество id>_<id1>_<id2>" и это здорово сокращало длину URL.
Здравствуйте, Vladek, Вы писали:
V>Игрался с параметрами в Web.config
Норм. вариант, если делается типичное энтерпрайз single-page js-приложение,
работающее в одном из браузеров хрома, версии 50.x.x.x.x, max length
V>Аргумент у метода сервиса был простой строкой, которая парсилась и превращалась обратно в массив. Что-то вроде..
Норм. вариант. как частный случай для небольшого массива.
Что бы в js не пришлось вручную парсить, массивы обычно передают ввиде json arr(где ','-разделитель).
Підтримати Україну у боротьбі з країною-терористом.
Здравствуйте, #John, Вы писали:
J>Если переделать http, для современного веба, то по правильному http get — надо убать вообще. J>http post надо кешировать как сейчас http get
Зачем такие сложности? Поддержка передачи параметров в "body" вполне решила бы проблему с длиной URL.
Здравствуйте, Artem Korneev, Вы писали:
J>>Если переделать http, для современного веба, то по правильному http get — надо убать вообще. J>>http post надо кешировать как сейчас http get
AK>Зачем такие сложности? Поддержка передачи параметров в "body" вполне решила бы проблему с длиной URL.
Только по стандарту это может не работать. Если ты передаёшь body в get, то сервер SHOULD игнорировать. Информация возвращаемая должна зависеть только от url. https://tools.ietf.org/html/rfc2616#section-4.3
if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
Т.е. один из сильных аргументов rest "а давайте чтобы всё быстрее заработало — поставим обычный кеширующий http прокси" — вдруг всё поломает, т.к. прокси (да и любые другие компоненты) может игнорировать тело get и иметь ограничение на длину url.
Как последнее средство — попробовать передизайнить ваш API чтобы не приходилось слать большие списки в get.
Ещё можно свой http verb ввести, это стандарт позволяет.
Так что при всём богатстве выбора — альтернативы post нет.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
AK>>Зачем такие сложности? Поддержка передачи параметров в "body" вполне решила бы проблему с длиной URL. ·>Только по стандарту это может не работать.
Здравствуйте, Artem Korneev, Вы писали:
AK>·>Только по стандарту это может не работать.
AK>Разумеется. Поэтому я и написал "решила бы".
Тут ведь как. Если подумать, то это ограничение get возникло не на пустом месте. Оно позволяет кеши, балансеры и прочее реализовывать эффективно. Кешировать по небольшому урлу имеет смысл, а для произвольного размера body вряд ли получится сделать что-то полезное.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, α, Вы писали:
AK>>Пилим мы REST-сервисы для проекта. Стараемся следовать рекоммендациям для RESTful-архитектур, но иногда не получается. Вот, например, намедни коллега добавила метод с такой сигнатурой α>Вообще, если речь идёт о fhir, то в его спецификации прямо все расписано, как делать запросы и каким http-методом, разве не? α>Согласно спецификации можно и GET и POST
Да.. но там всё-таки POST используется для "search", т.е. выборки по каким-то фильтрам, а не просто для получения по ID.
Вот для запроса по одному ID там по спецификации требуется GET. А запроса по нескольким ID в спецификации нет — это мелкие дополнения нашей платформы. Всё-таки мы склоняемся к тому, что запрос по нескольким идентификаторам тоже должен быть GET.
Здравствуйте, Vladek, Вы писали:
V> Игрался с параметрами в Web.config
По-моему, нету у нас web.config Ну или я его не нашёл.
Шаблон проекта у нас не совсем обычный. Мы пилим микросервисы под Azure Service Fabric. А оно поддерживает self-hosted WebAPI сервисы через nuget-пакеты Owin. Т.е. там потом приложение запускается на кластере Azure Service Fabric и уже из него стартует WebAPI-сервис. Файла web.config там нет.
Наверное можно ещё какими-то параметрами инициализации в коде поиграться чтоб добиться того же эффекта. Но я вчера опытным путём установил, что сервис нормально принимает строки до 16Kb — вполне достаточно для наших нужд. Правда, я это тестировал на локальном эмуляторе Azure Service Fabric. Но вроде на то он и эмулятор чтоб предоставлять примерно тот же рантайм, что и реальное облако. В любом случае, надо будет ещё в облаке всё это потестировать.
Здравствуйте, ·, Вы писали:
·>Кешировать по небольшому урлу имеет смысл, а для произвольного размера body вряд ли получится сделать что-то полезное.
Так принципиальной разницы нет — урл тоже теоретически безразмерный. Стандарт не ограничивает. На практике установлено, что ASP.NET поддерживает, как минимум, ~16Kb в параметрах URL. А при желании можно и больше настроить.
Здравствуйте, Artem Korneev, Вы писали:
AK>·>Кешировать по небольшому урлу имеет смысл, а для произвольного размера body вряд ли получится сделать что-то полезное.
AK>Так принципиальной разницы нет — урл тоже теоретически безразмерный. Стандарт не ограничивает. На практике установлено, что ASP.NET поддерживает, как минимум, ~16Kb в параметрах URL. А при желании можно и больше настроить.
Зато он говорит, что можно выкинуть 414 uri too long, а значит это может сделать любой промежуточный софт на пути http. Т.е. основывать свой rest api на произвольной длины урлах я бы не советовал.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Artem Korneev, Вы писали:
AK>Вопрос — а допустимы ли такие фокусы в правильных REST-сервисах? Ну т.е. мне вот с одной стороны бросается в глаза такой косяк, но в то же время в описаниях REST-архитектур я не смог найти запрета на использование POST запросов вместо GET, для запроса данных.
С мотивацией "ну ведь в GET может не влезть" категорически недопустимы.
AK>Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
По человечески это делается через POST метод %create_operation%, который принимает аргументы операции и возвращает токен. Затем по этому токену можно получить результат. Достоинства: идеологически верно, гарантированно не вызывает проблем с HTTP миддлварью, позволяет безболезненно прикрутить CQRS в реализации.
P>По человечески это делается через POST метод %create_operation%, который принимает аргументы операции и возвращает токен. Затем по этому токену можно получить результат. Достоинства: идеологически верно, гарантированно не вызывает проблем с HTTP миддлварью, позволяет безболезненно прикрутить CQRS в реализации.
Блин, вот реально огромная благодарность за столь очевидный, но мне в свое время
P>По человечески это делается через POST метод %create_operation%, который принимает аргументы операции и возвращает токен. Затем по этому токену можно получить результат. Достоинства: идеологически верно, гарантированно не вызывает проблем с HTTP миддлварью, позволяет безболезненно прикрутить CQRS в реализации.
Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно.
Y>Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно.
Отчасти верно, так как POST по определению может менять/создавать данные на сервере. Тут более уместен вопрос, сколько времени должен храниться на сервере результат выполнения операции, и соответственно время действия токена — через какое-то время результат операции при тех же аргументах станет уже другим (данные, по которым выполняется запрос поменялись) и токен надо уже делать недействительным.
Y>>Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно.
A>Отчасти верно, так как POST по определению может менять/создавать данные на сервере. Тут более уместен вопрос, сколько времени должен храниться на сервере результат выполнения операции, и соответственно время действия токена — через какое-то время результат операции при тех же аргументах станет уже другим (данные, по которым выполняется запрос поменялись) и токен надо уже делать недействительным.
Ну ОК, я просто подумал про хранение в сессии, а имеется в виду, что создаётся collection для операций, и сервер её чистит по расписанию.
Здравствуйте, andrey82, Вы писали:
A>Отчасти верно, так как POST по определению может менять/создавать данные на сервере. Тут более уместен вопрос, сколько времени должен храниться на сервере результат выполнения операции, и соответственно время действия токена — через какое-то время результат операции при тех же аргументах станет уже другим (данные, по которым выполняется запрос поменялись) и токен надо уже делать недействительным.
Т.е. появляется куча проблем. Мало того, это делает сервис stateful, т.е. лишняя головная боль для load balancer, вставляя палки в колёса scalability. Увеличивает latency — нужно два запроса вместо одного.
Не понимаю, в чём тогда преимущество такого токена? Зачем отдавать токен, если можно отдать данные сразу?
Можно, конечно, придумать ситуации когда это решение лучше, например, когда результаты большие и нужна возможность докачки при обрыве соединения. Но в большинстве случаев "дай мне профили для этих 500 юзеров" лучше подойдёт POST.
Кстати, если так хочется что-то более менее стандартное, можно посмотреть в сторону batch requests, типа такого: http://www.odata.org/documentation/odata-version-3-0/batch-processing/
Т.е. POST-ится "Content-Type: multipart/mixed" c пачкой GET-ов в "Content-Type: application/http".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, andrey82, Вы писали:
Y>>Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно.
A>Отчасти верно, так как POST по определению может менять/создавать данные на сервере. Тут более уместен вопрос, сколько времени должен храниться на сервере результат выполнения операции, и соответственно время действия токена — через какое-то время результат операции при тех же аргументах станет уже другим (данные, по которым выполняется запрос поменялись) и токен надо уже делать недействительным.
Зачем хранить токен операции? Назначить соотв. операции гуид и poll'ить по гуиду.
Здравствуйте, yenik, Вы писали:
P>>По человечески это делается через POST метод %create_operation%, который принимает аргументы операции и возвращает токен. Затем по этому токену можно получить результат. Достоинства: идеологически верно, гарантированно не вызывает проблем с HTTP миддлварью, позволяет безболезненно прикрутить CQRS в реализации.
Y>Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно.
Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом.
Здравствуйте, Sharov, Вы писали:
A>>Отчасти верно, так как POST по определению может менять/создавать данные на сервере. Тут более уместен вопрос, сколько времени должен храниться на сервере результат выполнения операции, и соответственно время действия токена — через какое-то время результат операции при тех же аргументах станет уже другим (данные, по которым выполняется запрос поменялись) и токен надо уже делать недействительным. S>Зачем хранить токен операции? Назначить соотв. операции гуид и poll'ить по гуиду.
Не понял. Этот гуид и будет играть роль токена. Т.е. на сервере нужно сохранять маппинг между результатом операции и гуидом. Вопрос — как долго хранить этот маппинг.
Y>>Между запросами эта операция должна храниться на сервере? Едва ли это идеологически верно. S>Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом.
А если клиенты не будут всегда (будут не всегда) останавливать? Утечка ресурсов?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Artem Korneev, Вы писали:
AK>·>Зато он говорит, что можно выкинуть 414 uri too long, а значит это может сделать любой промежуточный софт на пути http. AK>Стандарт рекомендует поддерживать как минимум 8000 октетов в URI, что уже плохо увязывается с понятием "небольшой URL".
В общем-то относительно небольшой, те же 500 id-шников может уже и не влезть.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
S>>Зачем хранить токен операции? Назначить соотв. операции гуид и poll'ить по гуиду. ·>Не понял. Этот гуид и будет играть роль токена. Т.е. на сервере нужно сохранять маппинг между результатом операции и гуидом. Вопрос — как долго хранить этот маппинг.
Ага, тут теперь я понял.
S>>Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом. ·>А если клиенты не будут всегда (будут не всегда) останавливать? Утечка ресурсов?
И? Создание html страницы -- это тоже утечка ресурсов. Любое post -- утечка ресурсов. Не вижу проблемы. Решать должен клиент, токен то имеется.
Здравствуйте, Sharov, Вы писали:
S>>>Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом. S>·>А если клиенты не будут всегда (будут не всегда) останавливать? Утечка ресурсов? S>И? Создание html страницы -- это тоже утечка ресурсов. Любое post -- утечка ресурсов. Не вижу проблемы.
Почему _любое_ post — утечка ресурсов?
S>Решать должен клиент, токен то имеется.
Клиент может токен потерять или сломать. Или клиент вообще может умереть.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
·>Здравствуйте, Sharov, Вы писали:
S>>>>Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом. S>>·>А если клиенты не будут всегда (будут не всегда) останавливать? Утечка ресурсов? S>>И? Создание html страницы -- это тоже утечка ресурсов. Любое post -- утечка ресурсов. Не вижу проблемы. ·>Почему _любое_ post — утечка ресурсов?
Блин, по определению. Реальность такова, что чтобы создать что-то необходимо использовать ресурсы (утечка ресурсов на создание). Если мы конечно же говорим о post как о создании ресурсов, а не о get с телом
S>>Решать должен клиент, токен то имеется. ·>Клиент может токен потерять или сломать. Или клиент вообще может умереть.
И? Таймауту предосмотреть для сессии. Еще чего-нибудь придумать. Не вижу здесь проблемы.
Здравствуйте, Sharov, Вы писали:
S>>>>>Необязательно храниться, она может и выполняться. А остановить ее можно либо delete'ом либо put'ом. S>>>·>А если клиенты не будут всегда (будут не всегда) останавливать? Утечка ресурсов? S>>>И? Создание html страницы -- это тоже утечка ресурсов. Любое post -- утечка ресурсов. Не вижу проблемы. S>·>Почему _любое_ post — утечка ресурсов? S>Блин, по определению. Реальность такова, что чтобы создать что-то необходимо использовать ресурсы (утечка ресурсов на создание). Если мы конечно же говорим о post как о создании ресурсов, а не о get с телом
Теоретически — созданное не всегда нужно сохранять на сервере. Например, в типичном сценарии POST может создать transaction id, используя UUID_Gen или email confirmation с использованием HMAC.
S>>>Решать должен клиент, токен то имеется. S>·>Клиент может токен потерять или сломать. Или клиент вообще может умереть. S>И? Таймауту предосмотреть для сессии. Еще чего-нибудь придумать. Не вижу здесь проблемы.
Ну вот... внезапно сессия появилась. А по идее самый производительный rest — stateless.
Таймауты как-то подбирать надо...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Ресурсы-то в любом случае затрачиваются. В данном случае проц+ram+сетевуха.
S>>И? Таймауту предосмотреть для сессии. Еще чего-нибудь придумать. Не вижу здесь проблемы. ·>Ну вот... внезапно сессия появилась. А по идее самый производительный rest — stateless.
Таки rest будет stateless вне зависимости от сессии. Каждый последующий вызов никак не связан с предыдущим. Сессия здесь побоку.
·>Таймауты как-то подбирать надо...
И не говорите, злости не хватает. А по утрам вообще просыпаться и вставать надо.
Здравствуйте, Sharov, Вы писали:
S>·>Теоретически — созданное не всегда нужно сохранять на сервере. Например, в типичном сценарии POST может создать transaction id, используя UUID_Gen или email confirmation с использованием HMAC. S>Ресурсы-то в любом случае затрачиваются. В данном случае проц+ram+сетевуха.
Это "возобновляемые ресурсы". Я об утечках. Если поставить сервак и замуровать, то в случае когда утечек нет, он может работать вечно, пока электричество есть. А если есть утечки, то через какое-то время будет "no space on device" или "out of memory".
Можно конечно эти ресурсы грохать по таймауту (expire), но тогда надо как-то доказать, что ресурсов будет достаточно для данного таймаута. Если таймаут сликшом короткий — клиенты могут не успевать. Если слишком длинный — нужен больший размер хранилища.
S>>>И? Таймауту предосмотреть для сессии. Еще чего-нибудь придумать. Не вижу здесь проблемы. S>·>Ну вот... внезапно сессия появилась. А по идее самый производительный rest — stateless. S>Таки rest будет stateless вне зависимости от сессии. Каждый последующий вызов никак не связан с предыдущим. Сессия здесь побоку.
Неверно, он связан токеном — второй вызов можно сделать только после первого и в то же место.
Представь это со стороны load balancer. Первый запрос отправляется узлуА и он создаёт токен, второй запрос отправляется узлуБ, потому что узелА нагружен больше, или вообще сдох. Откуда узелБ возьмёт результат?
S>·>Таймауты как-то подбирать надо... S>И не говорите, злости не хватает. А по утрам вообще просыпаться и вставать надо.
Это лишняя сложность и нагрузка. Где же KISS?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
·>Неверно, он связан токеном — второй вызов можно сделать только после первого и в то же место. ·>Представь это со стороны load balancer. Первый запрос отправляется узлуА и он создаёт токен, второй запрос отправляется узлуБ, потому что узелА нагружен больше, или вообще сдох. Откуда узелБ возьмёт результат?
Из общего хранилища / реплицированной копии хранилища узлаА, какие еще варианты?
S>>Ресурсы-то в любом случае затрачиваются. В данном случае проц+ram+сетевуха. ·>Это "возобновляемые ресурсы". Я об утечках.
Я понял, поэтому и предложил таймауты.
·>Можно конечно эти ресурсы грохать по таймауту (expire), но тогда надо как-то доказать, что ресурсов будет достаточно для данного таймаута. Если таймаут сликшом короткий — клиенты могут не успевать. Если слишком длинный — нужен больший размер хранилища.
Нормальная инженерная проблема, решить чем пожертвовать.
·>Неверно, он связан токеном — второй вызов можно сделать только после первого и в то же место. ·>Представь это со стороны load balancer. Первый запрос отправляется узлуА и он создаёт токен, второй запрос отправляется узлуБ, потому что узелА нагружен больше, или вообще сдох. Откуда узелБ возьмёт результат?
В данном конкретном случае, очевидно, что писать в базу или куда еще, чтобы по токену можно было получить результат.
Здравствуйте, Sharov, Вы писали:
S>·>Можно конечно эти ресурсы грохать по таймауту (expire), но тогда надо как-то доказать, что ресурсов будет достаточно для данного таймаута. Если таймаут сликшом короткий — клиенты могут не успевать. Если слишком длинный — нужен больший размер хранилища. S>Нормальная инженерная проблема, решить чем пожертвовать.
Вначале создали проблему двумя запросами, а теперь её героически решаем не жалея жертв...
S>>>Таки rest будет stateless вне зависимости от сессии. Каждый последующий вызов никак не связан с предыдущим. Сессия здесь побоку. S>·>Неверно, он связан токеном — второй вызов можно сделать только после первого и в то же место. S>·>Представь это со стороны load balancer. Первый запрос отправляется узлуА и он создаёт токен, второй запрос отправляется узлуБ, потому что узелА нагружен больше, или вообще сдох. Откуда узелБ возьмёт результат? S>В данном конкретном случае, очевидно, что писать в базу или куда еще, чтобы по токену можно было получить результат.
И где же обещанное "stateless"?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
S>>В данном конкретном случае, очевидно, что писать в базу или куда еще, чтобы по токену можно было получить результат. ·>И где же обещанное "stateless"?
По кругу ходим: мы вроде договорились, что из-зи токена у нас не stateless, а "stateless"...
Здравствуйте, Sharov, Вы писали:
S>>>В данном конкретном случае, очевидно, что писать в базу или куда еще, чтобы по токену можно было получить результат. S>·>И где же обещанное "stateless"? S>По кругу ходим: мы вроде договорились, что из-зи токена у нас не stateless, а "stateless"...
Ничего не понял. не stateless, а "stateless" что значит?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
S>>По кругу ходим: мы вроде договорились, что из-зи токена у нас не stateless, а "st
ateless"...
·>Ничего не понял. не stateless, а "stateless" что значит?
Здравствуйте, Artem Korneev, Вы писали:
AK>Далее.. позвал я ихнего техлида и он мне пояснил причину такого кода — в кач-ве параметра к запросу передаётся массив идентификаторов. Каждый идентификатор — около 30 символов. Если передавать их как параметры GET-запроса, то легко массив из 60 идентификаторов займёт уже пару килобайт и они не уверены, не превысит ли это лимитов длины HTTP-запроса.
AK>Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
AK>Посоветуйте. Кто-нибудь наверняка ведь сталкивался с ситуацией, когда для запроса данных нужно передать несколько десятков параметров. Может какие-то примеры есть среди общеизвестных REST-сервисов?
IMHO, мотивация вполне разумная. Я бы не парился и делал через POST. У нас например все DELETE и PUT блокируются на роутерах, в результате все через POST.
Если упереться рогом и требовать соответствия канону, можно так ничего и не сделать.
Здравствуйте, Sharov, Вы писали:
S>·>Почему _любое_ post — утечка ресурсов?
S>Блин, по определению. Реальность такова, что чтобы создать что-то необходимо использовать ресурсы (утечка ресурсов на создание). Если мы конечно же говорим о post как о создании ресурсов, а не о get с телом
Вы путаете утечку ресурсов(leak) с использованием ресурсов(usage).
Здравствуйте, pestis, Вы писали:
P>По человечески это делается через POST метод %create_operation%, который принимает аргументы операции и возвращает токен. Затем по этому токену можно получить результат. Достоинства: идеологически верно, гарантированно не вызывает проблем с HTTP миддлварью, позволяет безболезненно прикрутить CQRS в реализации.
Я не большой специалист по вебовскому программированию. А скажете, правильно ли я понимаю, что для реализации всего этого богатства потребуется где-то на стороне сервера создать запись в базе данных, которая будет связывать этот токен со стоящими за ним аргументами? Причем кто-то еще должен будет следить, чтобы уже не нужные/всеми забытые записи не накапливались.
Здравствуйте, Artem Korneev, Вы писали:
AK>Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
Я бы не парился, и сделал POST. Разбиение запросов — это всегда некоторый overhead. Временное хранение пачки аргументов на сервере с токеном для ссылки на них — это БОЛЬШОЙ overhead, плюс изрядные архитектурные сложности.
Стоит ли идеологическая чистота всех этих лишних накладных расходов?
Здравствуйте, Adnin, Вы писали:
A>Здравствуйте, Sharov, Вы писали:
S>>·>Почему _любое_ post — утечка ресурсов?
S>>Блин, по определению. Реальность такова, что чтобы создать что-то необходимо использовать ресурсы (утечка ресурсов на создание). Если мы конечно же говорим о post как о создании ресурсов, а не о get с телом
A>Вы путаете утечку ресурсов(leak) с использованием ресурсов(usage).
Я имел ввиду преднамеренную(ожидаемую) утечку ресурсов. А leak непреднамеренная -- утечка памяти и т.д.
Здравствуйте, Artem Korneev, Вы писали:
AK>Вот второй, более важный вопрос — как такие вещи делаются по-человечески? Вот если нужно поддерживать GET-запросы, в которых длина аргументов тянет на пяток килобайт, как быть? Требовать разбивать запросы? Или плюнуть и запрашивать данные через POST-запрос, передавая параметры в теле запроса? Или настраивать Web-сервер, чтоб увеличить максимальную длину запроса?
Pzz>Я не большой специалист по вебовскому программированию. А скажете, правильно ли я понимаю, что для реализации всего этого богатства потребуется где-то на стороне сервера создать запись в базе данных, которая
будет связывать этот токен со стоящими за ним аргументами? Причем кто-то еще должен будет следить, чтобы уже не нужные/всеми забытые записи не накапливались.
Неправильно понимаешь, все современные вебные фреймворки имеют временное хранилище для таких случаев и автоматически умеют следить за временем жизни записей. Правильный воркфлоу такой:
1. Получили реквест на поиск
2. Запустили в фоне поисковый запрос
3. Вернули токен не дожидаясь окончания поиска
4. Поисковый запрос отработал и сложил результаты во временное хранилище
5. Получили запрос по токену
6. Вернули результаты
Здравствуйте, pestis, Вы писали:
P>Неправильно понимаешь, все современные вебные фреймворки имеют временное хранилище для таких случаев и автоматически умеют следить за временем жизни записей. Правильный воркфлоу такой: P>1. Получили реквест на поиск P>2. Запустили в фоне поисковый запрос P>3. Вернули токен не дожидаясь окончания поиска P>4. Поисковый запрос отработал и сложил результаты во временное хранилище P>5. Получили запрос по токену P>6. Вернули результаты
Интересно, что в этой конструкции перевешивает, выигрыш от распараллеливания поиска с сетевым общением между клиентом и сервером, или проигрыш от удваивания количества запросов и увеличения нагрузки на сервер?
25.11.2016 9:06, pestis пишет:
>Правильный воркфлоу такой: > 1. Получили реквест на поиск > 2. Запустили в фоне поисковый запрос > 3. Вернули токен не дожидаясь окончания поиска > 4. Поисковый запрос отработал и сложил результаты во временное хранилище > 5. Получили запрос по токену > 6. Вернули результаты
Такой воркфлоу представляется правильным только для очень длительных
запросов или генерации репортов (в этом случае их обычно складывают не
во временное а в более-менее постоянное хранилище).
В остальных случаях от п. 2-5 будет одно зло. Либо надо постоянно
опрашивать сервер, что или будет его нагружать, или (если период опроса
достаточно велик) приведет к тому, что рез-т уже готов, а пользователь
его всё никак не получает. Либо держать открытый вебсокет.
Здравствуйте, Vladek, Вы писали:
V> <httpRuntime targetFramework="4.5.1" maxUrlLength="10999" maxQueryStringLength="2097151" />
Лимит длины HTTP-запроса — он не только у сервера, но и у клиента. Например у IE это ~2K символов.
V>Передавал параметры в сервис в закодированном виде, по максимум убрав лишнюю информацию (там много чего можно сократить и выбросить). Аргумент у метода сервиса был простой строкой, которая парсилась и превращалась обратно в массив. Что-то вроде "<количество id>_<id1>_<id2>" и это здорово сокращало длину URL.
А тут вы не только не "решили проблему", но на ровном месте добавили себе гарантированныйе грабли для id вида [this_is_my_custom_id].
Здравствуйте, Pzz, Вы писали:
Pzz>Интересно, что в этой конструкции перевешивает, выигрыш от распараллеливания поиска с сетевым общением между клиентом и сервером, или проигрыш от удваивания количества запросов и увеличения нагрузки на сервер?
Перевешивает удобство пользователя. Смотри, если в методе поиска параметры не пролазят в GET запрос, значит потенциально это долгий запрос потому что эти параметры не пролезут и в кэши. Значит разумнее показать пользователю спиннер вместо того чтобы тупить на GET запросе.
Здравствуйте, pestis, Вы писали:
Pzz>>Интересно, что в этой конструкции перевешивает, выигрыш от распараллеливания поиска с сетевым общением между клиентом и сервером, или проигрыш от удваивания количества запросов и увеличения нагрузки на сервер?
P>Перевешивает удобство пользователя. Смотри, если в методе поиска параметры не пролазят в GET запрос, значит потенциально это долгий запрос потому что эти параметры не пролезут и в кэши. Значит разумнее показать пользователю спиннер вместо того чтобы тупить на GET запросе.
Спиннер — это чего мы на экране рисуем, способ передачи N параметров — это вообще транспортный уровень, раскидывание одного запроса на два с обсчетом в фоне — это вопрос архитектуры. Это вообще разные вещи, они не связаны друг с другом. Никто не мешает послать долгий асинхронный GET, и одновременно рисовать хоть котиков на экране.
Здравствуйте, Pzz, Вы писали:
Pzz>Спиннер — это чего мы на экране рисуем, способ передачи N параметров — это вообще транспортный уровень, раскидывание одного запроса на два с обсчетом в фоне — это вопрос архитектуры. Это вообще разные вещи, они не связаны друг с другом. Никто не мешает послать долгий асинхронный GET, и одновременно рисовать хоть котиков на экране.
Мешает архитектура браузера который не дает исполнять больше нескольких HTTP запросов одновременно.
Здравствуйте, pestis, Вы писали:
Pzz>>Спиннер — это чего мы на экране рисуем, способ передачи N параметров — это вообще транспортный уровень, раскидывание одного запроса на два с обсчетом в фоне — это вопрос архитектуры. Это вообще разные вещи, они не связаны друг с другом. Никто не мешает послать долгий асинхронный GET, и одновременно рисовать хоть котиков на экране.
P>Мешает архитектура браузера который не дает исполнять больше нескольких HTTP запросов одновременно.
Во-первых, это не правда. Несколько XmlHttpRequest могут исполняться параллельно.
Во-вторых, конкретно для того, чтобы рисовать спиннер, пока мы ждем ответа на долгий GET, больше одного запроса и не нужно.
В третьих, если исполнение запроса занимает много времени на сервере, клиенту совершенно не легче от того, что он разобъет этот запрос на два.
Здравствуйте, pestis, Вы писали:
P>Неправильно понимаешь, все современные вебные фреймворки имеют временное хранилище для таких случаев и автоматически умеют следить за временем жизни записей. Правильный воркфлоу такой: P>1. Получили реквест на поиск P>2. Запустили в фоне поисковый запрос P>3. Вернули токен не дожидаясь окончания поиска P>4. Поисковый запрос отработал и сложил результаты во временное хранилище P>5. Получили запрос по токену P>6. Вернули результаты
bnk У нас например все DELETE и PUT блокируются на роутерах,
Поясни, плиз.
Так работают роутеры, локализованные для вашей страны? Или я что-то не так понял?
Здравствуйте, Mihas, Вы писали:
M>bnk У нас например все DELETE и PUT блокируются на роутерах, M>Поясни, плиз. M>Так работают роутеры, локализованные для вашей страны? Или я что-то не так понял?
Не, не для страны конечно
Внутри организации, где сейчас работаю (большая гос. контора), заблокировано все кроме POST и GET.
Т.е. у меня на работе 2 машины по сути — одна с подключением к "внутренней" сети организации с кучей странных блокировок, которая к тому же физически отключена ото всего остального —
даже файлы туда на флешках перетаскивают, и другая — "нормальная", подключенная к интернету, без проблем с PUT и DELETE.
Понимаю, что сценарий довольно экзотический, но возможный.
Здравствуйте, Sharov, Вы писали:
S>Но желательно пересмотреть архитектуру, например когда надо сделать запросы по ид от 1 до 10
Судя по всему речь идет об UUID и задача типовая — обновить на клиенте пакетно или даже транзакционно список объектов.
Здравствуйте, ·, Вы писали:
·>Т.е. появляется куча проблем. Мало того, это делает сервис stateful, т.е. лишняя головная боль для load balancer, вставляя палки в колёса scalability. Увеличивает latency — нужно два запроса вместо одного.
На уровне контракта API достаточно сказать, что некоторая часть результатов возвращается сразу плюс ссылка на следующие. Начальная реализация сервера возвращает сразу всё, клиент сразу умеет дочитывать, в дальнейшем можно реализовать более умный сервер. Именно такая операция (синхронизация объектов по UUID или ссылкам на self) является достаточно распространенной, поэтому легко выделяется в архитектурный шаблон в коде.
Технически можно передавать тело в GET-запросе. Хотя это немного нестандартный подход и он не рекомендуется, очень многие клиенты и серверы позволяют это делать.